/* * This file is part of WebLookAndFeel library. * * WebLookAndFeel library is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * WebLookAndFeel library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with WebLookAndFeel library. If not, see . */ package com.alee.extended.filechooser; import com.alee.extended.drag.FileDragAndDropHandler; import com.alee.extended.layout.WrapFlowLayout; import com.alee.global.StyleConstants; import com.alee.laf.panel.WebPanel; import com.alee.managers.language.LanguageManager; import com.alee.managers.language.LanguageMethods; import com.alee.managers.language.updaters.LanguageUpdater; import com.alee.utils.*; import com.alee.utils.filefilter.AbstractFileFilter; import com.alee.utils.swing.WebTimer; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Custom component that acts as files container and allows drag & drop them. * Separate WebFilePlate component is created for each added file to display it. * * @author Mikle Garin */ public class WebFileDrop extends WebPanel implements LanguageMethods { /** * Remove file icon. */ public static final ImageIcon CROSS_ICON = new ImageIcon ( WebFileDrop.class.getResource ( "icons/cross.png" ) ); protected static final BasicStroke dashStroke = new BasicStroke ( 3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1f, new float[]{ 8f, 8f }, 0f ); protected int dashRound = StyleConstants.smallRound; protected int dashSideSpacing = 10; protected Color dropBackground = new Color ( 242, 242, 242 ); protected Color dropBorder = new Color ( 192, 192, 192 ); protected final List listeners = new ArrayList ( 1 ); protected boolean showRemoveButton = true; protected boolean showFileExtensions = false; protected boolean filesDragEnabled = false; protected int dragAction = TransferHandler.MOVE; protected boolean filesDropEnabled = true; protected boolean allowSameFiles = false; protected AbstractFileFilter fileFilter = null; protected boolean showDropText = true; protected float dropTextOpacity = 1f; protected String dropText = null; protected List selectedFiles = new ArrayList (); public WebFileDrop () { super ( "file-drop", new WrapFlowLayout ( true ) ); setUndecorated ( false ); setShadeWidth ( 25 ); // Default visual settings setFont ( SwingUtils.getDefaultLabelFont ().deriveFont ( Font.BOLD ).deriveFont ( 20f ) ); // Empty drop field text setShowDefaultDropText ( true ); // Files TransferHandler setTransferHandler ( new FileDragAndDropHandler () { @Override public boolean isDropEnabled () { return filesDropEnabled; } @Override public boolean filesDropped ( final List files ) { // Adding dragged files addSelectedFiles ( files ); return true; } } ); // Focus "catcher" addMouseListener ( new MouseAdapter () { @Override public void mousePressed ( final MouseEvent e ) { WebFileDrop.this.requestFocusInWindow (); } } ); // Background animation listener addFileSelectionListener ( new FilesSelectionListener () { private int filesCount = 0; private WebTimer animator = null; @Override public void selectionChanged ( final List selectedFiles ) { if ( filesCount == 0 && selectedFiles.size () > 0 ) { stopAnimator (); filesCount = selectedFiles.size (); animator = new WebTimer ( "WebFileDrop.textFadeOutTimer", StyleConstants.animationDelay, new ActionListener () { @Override public void actionPerformed ( final ActionEvent e ) { if ( dropTextOpacity > 0f ) { dropTextOpacity -= 0.1f; } dropTextOpacity = Math.max ( dropTextOpacity, 0f ); WebFileDrop.this.repaint (); if ( dropTextOpacity <= 0f ) { animator.stop (); } } } ); animator.start (); } else if ( filesCount > 0 && selectedFiles.size () == 0 ) { stopAnimator (); filesCount = selectedFiles.size (); animator = new WebTimer ( "WebFileDrop.textFadeInTimer", StyleConstants.animationDelay, new ActionListener () { @Override public void actionPerformed ( final ActionEvent e ) { if ( dropTextOpacity < 1f ) { dropTextOpacity += 0.1f; } dropTextOpacity = Math.min ( dropTextOpacity, 1f ); WebFileDrop.this.repaint (); if ( dropTextOpacity >= 1f ) { animator.stop (); } } } ); animator.start (); } } private void stopAnimator () { if ( animator != null && animator.isRunning () ) { animator.stop (); } } } ); } public boolean isShowDropText () { return showDropText; } public void setShowDropText ( final boolean showDropText ) { this.showDropText = showDropText; WebFileDrop.this.repaint (); } public boolean isFilesDragEnabled () { return filesDragEnabled; } public void setFilesDragEnabled ( final boolean filesDragEnabled ) { this.filesDragEnabled = filesDragEnabled; } public int getDragAction () { return dragAction; } public void setDragAction ( final int dragAction ) { this.dragAction = dragAction; } public boolean isFilesDropEnabled () { return filesDropEnabled; } public void setFilesDropEnabled ( final boolean filesDropEnabled ) { this.filesDropEnabled = filesDropEnabled; } public List getSelectedFiles () { return CollectionUtils.copy ( selectedFiles ); } public void setSelectedFiles ( final List files ) { removeAllSelectedFiles (); addSelectedFiles ( files ); } public void addSelectedFiles ( final List files ) { boolean changed = false; for ( final File file : files ) { changed = addSelectedFileImpl ( file ) || changed; } if ( changed ) { revalidate (); fireSelectionChanged (); } } public void addSelectedFiles ( final File... files ) { boolean changed = false; for ( final File file : files ) { changed = addSelectedFileImpl ( file ) || changed; } if ( changed ) { revalidate (); fireSelectionChanged (); } } public void addSelectedFile ( final File file ) { if ( addSelectedFileImpl ( file ) ) { revalidate (); fireSelectionChanged (); } } protected boolean addSelectedFileImpl ( final File file ) { if ( ( fileFilter == null || fileFilter.accept ( file ) ) && ( allowSameFiles || !FileUtils.containtsFile ( selectedFiles, file ) ) ) { add ( createFilePlate ( file ) ); selectedFiles.add ( file ); return true; } else { return false; } } public void removeAllSelectedFiles () { boolean changed = false; for ( final File file : CollectionUtils.copy ( selectedFiles ) ) { changed = removeSelectedFileImpl ( file, false ) || changed; } if ( changed ) { revalidate (); fireSelectionChanged (); } } public void removeSelectedFiles ( final List files ) { boolean changed = false; for ( final File file : files ) { changed = removeSelectedFileImpl ( file, true ) || changed; } if ( changed ) { revalidate (); fireSelectionChanged (); } } public void removeSelectedFiles ( final File... files ) { boolean changed = false; for ( final File file : files ) { changed = removeSelectedFileImpl ( file, true ) || changed; } if ( changed ) { revalidate (); fireSelectionChanged (); } } public void removeSelectedFile ( final File file ) { if ( removeSelectedFileImpl ( file, true ) ) { revalidate (); fireSelectionChanged (); } } protected boolean removeSelectedFileImpl ( final File file, final boolean animate ) { if ( FileUtils.containtsFile ( selectedFiles, file ) ) { for ( final WebFilePlate filePlate : getFilePlates ( file ) ) { if ( animate ) { filePlate.remove (); } else { remove ( filePlate ); selectedFiles.remove ( file ); } } return !animate; } else { return false; } } public List getFilePlates ( final File file ) { final List plates = new ArrayList ( 1 ); for ( int i = 0; i < getComponentCount (); i++ ) { final Component component = getComponent ( i ); if ( component instanceof WebFilePlate ) { final WebFilePlate filePlate = ( WebFilePlate ) component; if ( file.getAbsolutePath ().equals ( filePlate.getFile ().getAbsolutePath () ) ) { plates.add ( filePlate ); } } } return plates; } public boolean isAllowSameFiles () { return allowSameFiles; } public void setAllowSameFiles ( final boolean allowSameFiles ) { this.allowSameFiles = allowSameFiles; setSelectedFiles ( selectedFiles ); } public AbstractFileFilter getFileFilter () { return fileFilter; } public void setFileFilter ( final AbstractFileFilter fileFilter ) { this.fileFilter = fileFilter; setSelectedFiles ( selectedFiles ); } public boolean isShowRemoveButton () { return showRemoveButton; } public void setShowRemoveButton ( final boolean showRemoveButton ) { this.showRemoveButton = showRemoveButton; for ( int i = 0; i < getComponentCount (); i++ ) { ( ( WebFilePlate ) getComponent ( i ) ).setShowRemoveButton ( showRemoveButton ); } } public boolean isShowFileExtensions () { return showFileExtensions; } public void setShowFileExtensions ( final boolean showFileExtensions ) { this.showFileExtensions = showFileExtensions; for ( int i = 0; i < getComponentCount (); i++ ) { ( ( WebFilePlate ) getComponent ( i ) ).setShowFileExtensions ( showFileExtensions ); } } public Color getDropBackground () { return dropBackground; } public void setDropBackground ( final Color dropBackground ) { this.dropBackground = dropBackground; repaint (); } public Color getDropBorder () { return dropBorder; } public void setDropBorder ( final Color dropBorder ) { this.dropBorder = dropBorder; repaint (); } public int getDashRound () { return dashRound; } public void setDashRound ( final int dashRound ) { this.dashRound = dashRound; repaint (); } public int getDashSideSpacing () { return dashSideSpacing; } public void setDashSideSpacing ( final int dashSideSpacing ) { this.dashSideSpacing = dashSideSpacing; repaint (); } public String getDropText () { return dropText; } public void setDropText ( final String dropText ) { this.dropText = dropText; repaint (); } public void setShowDefaultDropText ( final boolean defaultDropText ) { if ( defaultDropText ) { setLanguage ( "weblaf.ex.filedrop.drop" ); } else { removeLanguage (); } repaint (); } public boolean isDropTextVisible () { return dropText != null && showDropText && dropTextOpacity > 0f; } protected WebFilePlate createFilePlate ( final File file ) { final WebFilePlate filePlate = new WebFilePlate ( file ); filePlate.setShowFileExtensions ( showFileExtensions ); // To block parent container events addMouseListener ( new MouseAdapter () { @Override public void mousePressed ( final MouseEvent e ) { requestFocusInWindow (); } } ); // Data change on removal filePlate.addCloseListener ( new ActionListener () { @Override public void actionPerformed ( final ActionEvent e ) { // Removing file from added files list selectedFiles.remove ( file ); // Inform that selected files changed fireSelectionChanged (); } } ); return filePlate; } @Override protected void paintComponent ( final Graphics g ) { super.paintComponent ( g ); if ( isDropTextVisible () ) { final Graphics2D g2d = ( Graphics2D ) g; final Composite old = GraphicsUtils.setupAlphaComposite ( g2d, dropTextOpacity ); final Object aa = GraphicsUtils.setupAntialias ( g2d ); final Insets bi = getInsets (); final int hd = Math.round ( dashStroke.getLineWidth () / 2 ); final int hd2 = Math.round ( dashStroke.getLineWidth () ); final int dashX = dashSideSpacing + bi.left; final int dashY = dashSideSpacing + bi.top; final int dashWidth = getWidth () - dashSideSpacing * 2 - bi.left - bi.right; final int dashHeight = getHeight () - dashSideSpacing * 2 - bi.top - bi.bottom; g2d.setPaint ( dropBackground ); g2d.fillRoundRect ( dashX + hd, dashY + hd, dashWidth - hd2, dashHeight - hd2, dashRound * 2, dashRound * 2 ); final Stroke os = GraphicsUtils.setupStroke ( g2d, dashStroke ); g2d.setPaint ( dropBorder ); g2d.drawRoundRect ( dashX, dashY, dashWidth, dashHeight, dashRound * 2, dashRound * 2 ); GraphicsUtils.restoreStroke ( g2d, os ); GraphicsUtils.restoreAntialias ( g2d, aa ); final FontMetrics fm = g2d.getFontMetrics (); if ( dashWidth >= fm.stringWidth ( dropText ) && dashHeight > fm.getHeight () ) { final Map hints = SwingUtils.setupTextAntialias ( g2d ); final Point ts = LafUtils.getTextCenterShear ( fm, dropText ); g2d.drawString ( dropText, dashX + dashWidth / 2 + ts.x, dashY + dashHeight / 2 + ts.y ); SwingUtils.restoreTextAntialias ( g2d, hints ); } GraphicsUtils.restoreComposite ( g2d, old ); } } public void addFileSelectionListener ( final FilesSelectionListener listener ) { listeners.add ( listener ); } public void removeFileSelectionListener ( final FilesSelectionListener listener ) { listeners.remove ( listener ); } protected void fireSelectionChanged () { for ( final FilesSelectionListener listener : CollectionUtils.copy ( listeners ) ) { listener.selectionChanged ( CollectionUtils.copy ( selectedFiles ) ); } } /** * Language methods */ /** * {@inheritDoc} */ @Override public void setLanguage ( final String key, final Object... data ) { LanguageManager.registerComponent ( this, key, data ); } /** * {@inheritDoc} */ @Override public void updateLanguage ( final Object... data ) { LanguageManager.updateComponent ( this, data ); } /** * {@inheritDoc} */ @Override public void updateLanguage ( final String key, final Object... data ) { LanguageManager.updateComponent ( this, key, data ); } /** * {@inheritDoc} */ @Override public void removeLanguage () { LanguageManager.unregisterComponent ( this ); } /** * {@inheritDoc} */ @Override public boolean isLanguageSet () { return LanguageManager.isRegisteredComponent ( this ); } /** * {@inheritDoc} */ @Override public void setLanguageUpdater ( final LanguageUpdater updater ) { LanguageManager.registerLanguageUpdater ( this, updater ); } /** * {@inheritDoc} */ @Override public void removeLanguageUpdater () { LanguageManager.unregisterLanguageUpdater ( this ); } }