package jp.crwdev.app.gui; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.InputStream; import java.util.HashMap; import java.util.LinkedList; import javax.swing.DefaultListModel; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; import javax.swing.SpringLayout; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.MouseInputAdapter; import jp.crwdev.app.BufferedImageIO; import jp.crwdev.app.EventObserver; import jp.crwdev.app.EventObserver.OnEventListener; import jp.crwdev.app.imagefilter.ImageFilterParam; import jp.crwdev.app.imagefilter.ResizeFilter; import jp.crwdev.app.interfaces.IImageFileInfo; import jp.crwdev.app.interfaces.IImageFileInfoList; @SuppressWarnings("serial") public class ThumbnailView extends JFrame implements OnEventListener{ // private JScrollPane mScrollPane; private DefaultListModel mModel; private JList mList; private IImageFileInfoList mInfoList; private ImageFileInfoTable mInfoTable; // private boolean mWindowSizeMax = false; private ThumbnailLoadThread mThread = new ThumbnailLoadThread(); public ThumbnailView(){ super(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(new Rectangle(200, 200, 120*8+20, 150)); //setViewSize(mWindowSizeMax); mModel = new DefaultListModel(); mList = new JList(mModel); mList.setLayoutOrientation(JList.HORIZONTAL_WRAP); mList.setVisibleRowCount(1); mList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); mList.addListSelectionListener(new ListSelectionListener(){ @Override public void valueChanged(ListSelectionEvent e) { if(e.getValueIsAdjusting()){ return; } int selected = mList.getSelectedIndex(); if(mInfoTable != null){ //mInfoTable.selectItem(selected); mInfoTable.setRowSelectionInterval(selected, selected); } } }); mList.setCellRenderer(new ThumbnailRenderer()); JScrollPane scroll = new JScrollPane(mList, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); scroll.setWheelScrollingEnabled(true); // mScrollPane = scroll; //scroll.setBorder(new BevelBorder(BevelBorder.LOWERED)); SpringLayout layout = new SpringLayout(); setLayout(layout); Container contentPane = getContentPane(); contentPane.add(scroll); layout.putConstraint(SpringLayout.NORTH, scroll, 3, SpringLayout.NORTH, contentPane); layout.putConstraint(SpringLayout.SOUTH, scroll, -3, SpringLayout.SOUTH, contentPane); layout.putConstraint(SpringLayout.WEST, scroll, 10, SpringLayout.WEST, contentPane); layout.putConstraint(SpringLayout.EAST, scroll, -10, SpringLayout.EAST, contentPane); MouseInputAdapter adapter = new MouseInputAdapter(){ private Point prev; private Point winPos; @Override public void mouseClicked(MouseEvent e){ if(javax.swing.SwingUtilities.isRightMouseButton(e)){ JPopupMenu popup = new JPopupMenu(); String menuTitle = isAlwaysOnTop() ? "最前面表示しない" : "常に最前面表示"; JMenuItem item0 = new JMenuItem(menuTitle); item0.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { setAlwaysOnTop(!isAlwaysOnTop()); } }); popup.add(item0); // JMenuItem item1 = new JMenuItem("ウインドウサイズ変更"); // item1.addActionListener(new ActionListener(){ // @Override // public void actionPerformed(ActionEvent arg0) { // setViewSize(!mWindowSizeMax); // } // }); // popup.add(item1); JMenuItem item2 = new JMenuItem("非表示にする"); item2.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { setVisible(false); } }); popup.add(item2); popup.show(e.getComponent(), e.getX(), e.getY()); } } @Override public void mousePressed(MouseEvent e){ if(prev == null){ prev = new Point(e.getX(), e.getY()); } } @Override public void mouseReleased(MouseEvent e){ prev = null; } @Override public void mouseDragged(MouseEvent e){ Window window = ThumbnailView.this; if(prev == null){ prev = new Point(e.getX(), e.getY()); } int x = e.getX() - prev.x; int y = e.getY() - prev.y; winPos = window.getLocation(winPos); window.setLocation(winPos.x + x, winPos.y + y); } }; addMouseListener(adapter); addMouseMotionListener(adapter); setUndecorated(true); //setOpacity(0.5f); // setBackground(new Color(0, 0, 0)); getContentPane().setBackground(Color.GRAY); //setAlwaysOnTop(true); //setVisible(true); mThread.start(); } public void setViewSize(boolean maximum){ int width = 800; Dimension screenSize = new Dimension(800,600); try{ GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice graphicsDevice = graphicsEnvironment.getDefaultScreenDevice(); Rectangle rect = graphicsDevice.getDefaultConfiguration().getBounds(); //screenSize = rect.getSize(); width = rect.width; Rectangle desktopBounds = graphicsEnvironment.getMaximumWindowBounds(); if(maximum){ screenSize.setSize(desktopBounds.width, desktopBounds.height); } }catch(Exception ex){ ex.printStackTrace(); } // mWindowSizeMax = maximum; setBounds(width - screenSize.width, screenSize.height-150, screenSize.width, 150); // setSize(screenSize.width, 150); } public void setImageFileInfoTable(ImageFileInfoTable table){ mInfoTable = table; } public void setImageFileInfoList(IImageFileInfoList list){ mModel.clear(); for(ThumbnailPanel panel : mPanelMap.values()){ panel.release(); } mPanelMap.clear(); mInfoList = list; if(mInfoList != null){ for(int i=0; i<mInfoList.size(); i++){ mModel.addElement(mInfoList.get(i)); } } } private HashMap<IImageFileInfo, ThumbnailPanel> mPanelMap = new HashMap<IImageFileInfo, ThumbnailPanel>(); public ThumbnailPanel getThumbnailPanel(IImageFileInfo info){ if(mPanelMap.containsKey(info)){ return mPanelMap.get(info); } else{ ThumbnailPanel panel = new ThumbnailPanel(info); mPanelMap.put(info, panel); return panel; } } public BufferedImage getThumbnail(IImageFileInfo info){ InputStream in = info.getInputStream(); BufferedImage image = null; if(in != null){ image = BufferedImageIO.read(info.getInputStream(), info.isJpeg()); } else{ image = info.getImage(true); } ImageFilterParam param = new ImageFilterParam(); param.setResize(true); param.setResizeDimension(120, 120); ResizeFilter filter = new ResizeFilter(); image = filter.filter(image, param); return image; } public class ThumbnailLoadThread extends Thread { private LinkedList<ThumbnailPanel> mQueue = new LinkedList<ThumbnailPanel>(); private boolean mIsAbort = false; private Object mLock = new Object(); @Override public void run(){ ThumbnailPanel panel = null; mIsAbort = false; while(!mIsAbort){ try { synchronized(mLock){ mLock.wait(); } while(mQueue.size() > 0){ synchronized(mQueue){ panel = mQueue.removeLast(); } if(panel != null){ BufferedImage image = getThumbnail(panel.getImageFileInfo()); panel.setThumbnail(image); mList.repaint(); } } } catch (InterruptedException e) { e.printStackTrace(); } } } public void request(ThumbnailPanel panel){ synchronized(mQueue){ if(mQueue.size() > 15){ while(mQueue.size() > 15){ ThumbnailPanel removed = mQueue.removeLast(); if(removed != null){ removed.setLoading(false); } } } mQueue.push(panel); } synchronized(mLock){ mLock.notify(); } } public void release(){ mIsAbort = true; synchronized(mQueue){ mQueue.clear(); } synchronized(mLock){ mLock.notify(); } } } public class ThumbnailPanel extends JPanel { private static final int PanelWidth = 120; private static final int PanelHeight = 126; private BufferedImage mThumbnail; private IImageFileInfo mInfo; private boolean mLoading = false; public ThumbnailPanel(IImageFileInfo info){ setPreferredSize(new Dimension(PanelWidth, PanelHeight)); mInfo = info; } public IImageFileInfo getImageFileInfo(){ return mInfo; } public void setThumbnail(BufferedImage image){ mThumbnail = image; } public void setLoading(boolean loading){ mLoading = loading; } public void release(){ mThumbnail = null; mInfo = null; } @Override public void paint(Graphics g) { super.paint(g); if(mThumbnail == null && !mLoading){ mLoading = true; if(mThread != null){ mThread.request(this); } } if(mThumbnail != null){ int x = (PanelWidth - mThumbnail.getWidth())/2; int y = (PanelHeight - mThumbnail.getHeight())/2; g.drawImage(mThumbnail, x, y, null); } } } public class ThumbnailRenderer implements ListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JPanel panel; if(value instanceof IImageFileInfo){ IImageFileInfo info = (IImageFileInfo)value; panel = getThumbnailPanel(info); }else{ panel = new JPanel(); } if(isSelected){ panel.setBackground(Color.MAGENTA); }else if(cellHasFocus){ panel.setBackground(Color.CYAN); }else{ panel.setBackground(Color.LIGHT_GRAY); } return panel; } } @Override public void onEventReceived(int type, int arg1, int arg2, Object obj) { if(type == EventObserver.EventType_UpdateFileInfoList){ setImageFileInfoList((IImageFileInfoList)obj); } else if(type == EventObserver.EventType_ShowHide_ThumbnailView){ setVisible(isVisible() ? false : true); } } }