package open.dolphin.impl.img; import java.awt.Desktop; import java.awt.Window; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URL; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.FileTime; import java.text.MessageFormat; import java.util.*; import java.util.concurrent.ExecutionException; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.ProgressMonitor; import javax.swing.SwingWorker; import open.dolphin.client.AbstractChartDocument; import open.dolphin.client.Chart; import open.dolphin.client.ChartImpl; import open.dolphin.client.ClientContext; import open.dolphin.client.ImageEntry; import open.dolphin.helper.ImageHelper; import open.dolphin.infomodel.PatientModel; import org.apache.log4j.Level; /** * * @author Kazushi Minagawa, Digital Globe, Inc. */ public abstract class AbstractBrowser extends AbstractChartDocument { protected static final int MAX_IMAGE_SIZE = 120; protected static final int CELL_WIDTH_MARGIN = 20; protected static final int CELL_HEIGHT_MARGIN = 20; protected static final String PROP_BASE_DIR = "baseDir"; protected static final String PROP_DROP_ACTION = "dropAction"; protected static final String PROP_COLUMN_COUNT = "columnCount"; protected static final String PROP_SHOW_FILE_NAME = "showFileName"; protected static final String PROP_DISPLAY_ATTR = "displayAttr"; protected static final String PROP_SORT_ATTR = "sortAttr"; protected static final String PROP_SORT_ORDER = "sortOrder"; protected static final String[] ACCEPT_IMAGE_TYPES = {"jpg", "png", "bmp", "gif", "tif"}; protected static final String[] ACCEPT_DOC_TYPES = {"pdf", "doc","docx", "xls", "xlsx", "ppt","pptx"}; protected static final String[] ACCEPT_DOC_ICONS = {"icon_pdf", "icon_word","icon_word", "icon_excel", "icon_excel", "icon_power_point", "icon_power_point"}; protected final String DATE_FORMAT; protected ImageTableModel tableModel; protected JTable table; protected Desktop desktop; //protected boolean DEBUG; protected String imageBase; protected Properties properties; protected ProgressMonitor progressMonitor; protected boolean imageOrPDFIsExist; protected int imgCounter; protected String nowLocation; //s.oh^ 2014/05/07 PDF・画像タブの改善 protected boolean scanning; //s.oh$ public AbstractBrowser() { DATE_FORMAT = ClientContext.getMyBundle(AbstractBrowser.class).getString("dateFormat.imageBrowser"); if (Desktop.isDesktopSupported()) { desktop = Desktop.getDesktop(); } else { java.util.logging.Logger.getLogger(this.getClass().getName()).warning("Desktop is not supported"); } } public boolean isImageOrPDFIsExist() { return imageOrPDFIsExist; } public void setImageOrPDFIsExist(boolean b) { boolean old = imageOrPDFIsExist; imageOrPDFIsExist = b; if (old!=imageOrPDFIsExist) { ImageIcon icon = imageOrPDFIsExist ? ClientContext.getImageIconArias("icon_indicate_has_iamges_or_pdfs") : null; ChartImpl c = (ChartImpl)this.getContext(); c.setChartDocumentIconAt(icon, this.getUI()); } } /** * ブラウザ表示設定の規定値を返す。 * @return Properties */ protected Properties getProperties() { Properties defaults = new Properties(); defaults.setProperty(PROP_DROP_ACTION, "copy"); defaults.setProperty(PROP_COLUMN_COUNT, "5"); defaults.setProperty(PROP_SHOW_FILE_NAME, "true"); defaults.setProperty(PROP_DISPLAY_ATTR, "filename"); defaults.setProperty(PROP_SORT_ATTR, "lastModified"); defaults.setProperty(PROP_SORT_ORDER, "desc"); properties = new Properties(defaults); return properties; } protected boolean dropIsMove() { return (!properties.getProperty(PROP_DROP_ACTION).equals("copy")); } protected int columnCount() { return Integer.parseInt(properties.getProperty(PROP_COLUMN_COUNT)); } protected boolean showFilename() { return Boolean.parseBoolean(properties.getProperty(PROP_SHOW_FILE_NAME)); } protected boolean displayIsFilename() { return (properties.getProperty(PROP_DISPLAY_ATTR).equals("filename")); } protected boolean sortIsLastModified() { return (properties.getProperty(PROP_SORT_ATTR).equals("lastModified")); } protected boolean sortIsDescending() { return (properties.getProperty(PROP_SORT_ORDER).equals("desc")); } protected String getSuffix(String path) { int index = path!=null ? path.lastIndexOf('.') : -1; return index>=0 ? path.substring(index+1).toLowerCase(): null; } protected boolean isImage(String ext) { boolean ret = false; if (ext!=null) { for (String str : AbstractBrowser.ACCEPT_IMAGE_TYPES) { if (str.equals(ext)) { ret = true; break; } } } return ret; } protected int isDocument(String ext) { int ret = -1; if (ext!=null) { for (int i=0; i < AbstractBrowser.ACCEPT_DOC_TYPES.length; i++) { if (AbstractBrowser.ACCEPT_DOC_TYPES[i].equals(ext)) { ret = i; break; } } } return ret; } protected ImageEntry getEntryAt(int row, int col) { if (row != -1 && col != -1) { ImageEntry entry = (ImageEntry) tableModel.getValueAt(row, col); return entry; } return null; } /** * Chart がプラグインをタブへ追加する場合にコールする。 * 患者ディレクトリにファイルがあれば アイコンを返す。 * @param ctx * @return */ @Override public ImageIcon getIconInfo(Chart ctx) { ImageIcon icon; PatientModel pm = ctx.getPatient(); String pid = pm.getPatientId(); imageOrPDFIsExist = hasImageOrPDF(pid); icon = imageOrPDFIsExist ? ClientContext.getImageIconArias("icon_indicate_has_iamges_or_pdfs") : null; return icon; } /** * 指定した患者のディレクトリにファイルが存在する場合は true を返す。 */ private boolean hasImageOrPDF(String patientId) { boolean ret = false; if (getImageBase() != null && patientId!= null) { StringBuilder sb = new StringBuilder(); sb.append(getImageBase()); if (! getImageBase().endsWith(File.separator)) { sb.append(File.separator); } sb.append(patientId); String imgLoc = sb.toString(); Path imageDir = Paths.get(imgLoc); if (!Files.exists(imageDir) || !Files.isDirectory(imageDir)) { return false; } try { DirectoryStream<Path> ds = Files.newDirectoryStream(imageDir); for (Path p : ds) { String test = p.getFileName().toString(); if (!test.startsWith(".") && !test.startsWith("__")) { ret = true; break; } } } catch (Exception e) { } } return ret; } /** * PDFや画像が保管されているベース(共有)ディレクトリを返す。 * @return ベースディレクトリ名 */ public String getImageBase() { return this.imageBase; } /** * PDFや画像が保管されているベース(共有)ディレクトリを設定する。 * @param base ベースディレクトリ名 */ public void setImageBase(String base) { String old = this.imageBase; this.imageBase = base; if (!this.imageBase.equals(old)) { //s.oh^ 2013/04/19 パスが正しく表示されない //scan(imageBase); scan(getImgLocation()); //s.oh$ } } private void debug(URI uri, URL url, String path, String fileName) { java.util.logging.Logger.getLogger(this.getClass().getName()).fine("-------------------------------------------"); java.util.logging.Logger.getLogger(this.getClass().getName()).log(java.util.logging.Level.FINE, "URI = {0}", uri.toString()); java.util.logging.Logger.getLogger(this.getClass().getName()).log(java.util.logging.Level.FINE, "URL = {0}", url.toString()); java.util.logging.Logger.getLogger(this.getClass().getName()).log(java.util.logging.Level.FINE, "PATH = {0}", path); java.util.logging.Logger.getLogger(this.getClass().getName()).log(java.util.logging.Level.FINE, "File Name = {0}", fileName); } /** * 患者フォルダをスキャンする。 * @param imgLoc */ protected void scan(String imgLoc) { //s.oh^ 2014/05/07 PDF・画像タブの改善 if(scanning) { return; } scanning = true; //s.oh$ //String imgLoc = getImgLocation(); imgCounter = 0; if (valueIsNullOrEmpty(imgLoc)) { tableModel.clear(); this.setImageOrPDFIsExist(false); //s.oh^ 2014/05/07 PDF・画像タブの改善 scanning = false; //s.oh$ return; } Path imageDir = Paths.get(imgLoc); if (!Files.exists(imageDir) || !Files.isDirectory(imageDir)) { tableModel.clear(); this.setImageOrPDFIsExist(false); //s.oh^ 2014/05/07 PDF・画像タブの改善 scanning = false; //s.oh$ return; } final List<Path> paths = new ArrayList<>(); try { DirectoryStream<Path> ds = Files.newDirectoryStream(imageDir); for (Path p : ds) { String test = p.getFileName().toString(); if (!test.startsWith(".") && !test.startsWith("__")) { paths.add(p); } } } catch (Exception e) { } if (paths.isEmpty()) { tableModel.clear(); this.setImageOrPDFIsExist(false); //s.oh^ 2014/05/07 PDF・画像タブの改善 scanning = false; //s.oh$ return; } setImageOrPDFIsExist(true); final int total = paths.size(); SwingWorker worker = new SwingWorker<ArrayList<ImageEntry>, Void>() { @Override protected ArrayList<ImageEntry> doInBackground() throws Exception { ArrayList<ImageEntry> imageList = new ArrayList<>(); // Sort if (sortIsLastModified()) { // 最終更新日でソート if (sortIsDescending()) { Collections.sort(paths, (final Object o1, final Object o2) -> { try { FileTime l1 = Files.getLastModifiedTime((Path)o1); FileTime l2 = Files.getLastModifiedTime((Path)o2); return l2.compareTo(l1); } catch (Exception e) { } return 0; }); } else { Collections.sort(paths, (final Object o1, final Object o2) -> { try { FileTime l1 = Files.getLastModifiedTime((Path)o1); FileTime l2 = Files.getLastModifiedTime((Path)o2); return l1.compareTo(l2); } catch (Exception e) { } return 0; }); } } else { // filename でソート if (sortIsDescending()) { Collections.sort(paths, (final Object o1, final Object o2) -> { String n1 = ((Path)o1).getFileName().toString(); String n2 = ((Path)o2).getFileName().toString(); return n2.compareTo(n1); }); } else { Collections.sort(paths, (final Object o1, final Object o2) -> { String n1 = ((Path)o1).getFileName().toString(); String n2 = ((Path)o2).getFileName().toString(); return n1.compareTo(n2); }); } } int cnt = 0; for (Path path : paths) { //for (File file : imageFiles) { //s.oh^ 2013/11/07 複数画像表示できない不具合 //setProgress(100*(++cnt/total)); if(progressMonitor != null && progressMonitor.isCanceled()) { return imageList; } imgCounter += 1; double tmp = 100 * ((double)imgCounter / (double)total); if(imgCounter >= total) { setProgress(100); }else{ setProgress((int)tmp); } //s.oh$ URI uri = path.toUri(); URL url = uri.toURL(); String pathStr = path.toAbsolutePath().toString(); String fileName = path.getFileName().toString(); if(fileName.endsWith("Thumbs.db")) { continue; } //File f = path.toFile(); //s.oh^ 2014/05/07 PDF・画像タブの改善 //long last = Files.getLastModifiedTime(path).toMillis(); long last = 0; try{ Files.getLastModifiedTime(path).toMillis(); }catch(IOException e) { continue; } //s.oh$ debug(uri, url, pathStr, fileName); if (fileName.startsWith(".")||fileName.startsWith("__M")) { continue; } // ディレクトリの場合 if (Files.isDirectory(path)) { ImageEntry entry = new ImageEntry(); entry.setUrl(url.toString()); entry.setPath(pathStr); entry.setFileName(fileName); entry.setLastModified(last); entry.setImageIcon(ClientContext.getImageIconArias("icon_foldr")); entry.setDirectrory(true); // directory imageList.add(entry); continue; } // 拡張子のないファイル ToDo String suffix = getSuffix(fileName); if (suffix == null) { //s.oh^ 2014/07/29 PDF・画像タブの改善 //continue; suffix = "unnone"; //s.oh$ } boolean found = false; // 画像ファイル: Thumbnailを生成しアイコンへセットする for (int i = 0; i < ACCEPT_IMAGE_TYPES.length; i++) { if (ACCEPT_IMAGE_TYPES[i].equals(suffix)) { //s.oh^ 2014/05/07 PDF・画像タブの改善 //BufferedImage image = ImageIO.read(Files.newInputStream(path)); InputStream is = Files.newInputStream(path); BufferedImage image = ImageIO.read(is); //s.oh$ //s.oh^ 2013/03/15 不具合修正(表示できない画像対応) //image = ImageHelper.getFirstScaledInstance(image, MAX_IMAGE_SIZE); //ImageIcon icon = new ImageIcon(image); ImageIcon icon ; if(image == null) { icon = ClientContext.getImageIconArias("icon_default_document"); }else{ image = ImageHelper.getFirstScaledInstance(image, MAX_IMAGE_SIZE); icon = new ImageIcon(image); //s.oh^ 2014/02/24 PDF・画像ファイルの解放 image.flush(); //s.oh$ //s.oh^ 2014/05/07 PDF・画像タブの改善 is.close(); //s.oh$ } //s.oh$ ImageEntry entry = new ImageEntry(); entry.setUrl(url.toString()); entry.setPath(pathStr); entry.setFileName(fileName); entry.setLastModified(last); entry.setImageIcon(icon); imageList.add(entry); found = true; break; } } if (found) { continue; } // 文書: Doc Icon for (int i = 0; i < ACCEPT_DOC_TYPES.length; i++) { if (ACCEPT_DOC_TYPES[i].equals(suffix)) { ImageEntry entry = new ImageEntry(); entry.setUrl(url.toString()); entry.setPath(pathStr); entry.setFileName(fileName); entry.setLastModified(last); ImageIcon icon = ClientContext.getImageIconArias(ACCEPT_DOC_ICONS[i]); entry.setImageIcon(icon); imageList.add(entry); found = true; break; } } if (found) { continue; } // Default Icon ImageEntry entry = new ImageEntry(); entry.setUrl(url.toString()); entry.setPath(pathStr); entry.setFileName(fileName); entry.setLastModified(last); ImageIcon icon = ClientContext.getImageIconArias("icon_default_document"); entry.setImageIcon(icon); imageList.add(entry); } return imageList; } @Override protected void done() { try { tableModel.setImageList(get()); } catch (InterruptedException | ExecutionException ex) { ex.printStackTrace(System.err); } //s.oh^ 2014/05/07 PDF・画像タブの改善 scanning = false; //s.oh$ } }; worker.addPropertyChangeListener((PropertyChangeEvent evt) -> { if ("progress".equals(evt.getPropertyName())) { int progress = (Integer)evt.getNewValue(); progressMonitor.setProgress(progress); String fmt = ClientContext.getMyBundle(AbstractBrowser.class).getString("message.processing"); String message = String.format(fmt, imgCounter, total); progressMonitor.setNote(message); } }); String progressTitle = ClientContext.getMyBundle(AbstractBrowser.class).getString("title.sacaning"); progressMonitor = new ProgressMonitor(getUI(),progressTitle, "", 0, 100); progressMonitor.setProgress(0); worker.execute(); } //s.oh^ 2014/05/07 PDF・画像タブの改善 protected boolean isScanning(Window parent, String msg) { if(scanning) { String fmt = ClientContext.getMyBundle(AbstractBrowser.class).getString("messageFormat.reading"); MessageFormat msf = new MessageFormat(fmt); String message = msf.format(new Object[]{msg}); String title = ClientContext.getMyBundle(AbstractBrowser.class).getString("title.optionPane.reading"); // ? title with ... JOptionPane.showMessageDialog(parent, message, title, JOptionPane.WARNING_MESSAGE); return true; } return false; } //s.oh$ protected abstract String getImgLocation(); protected abstract void initComponents(); protected void openImage(ImageEntry entry) { if (desktop==null) { return; } try { //desktop.open(f); Path path = Paths.get(entry.getPath()); desktop.browse(path.toUri()); } catch (Exception ex) { java.util.logging.Logger.getLogger(this.getClass().getName()).fine(ex.getMessage()); } } protected String getNowLocation() { return nowLocation; } @Override public void start() { initComponents(); scan(getImgLocation()); } @Override public void stop() { } protected boolean valueIsNullOrEmpty(String test) { return (test==null || test.equals("")); } protected boolean valueIsNotNullNorEmpty(String test) { return !valueIsNullOrEmpty(test); } public JTable getTable() { return table; } //s.oh^ 2014/07/29 PDF・画像タブの改善 protected String checkDirName(String location, String name) { File dir = new File(location, name); if(dir.exists()) { for(int i = 2; i < 10000; i++) { dir = new File(location, String.format("%s(%d)", name, i)); if(!dir.exists()) { break; } } } return dir.getName(); } //s.oh$ }