All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.openfile.DefaultExternalDropHandler Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.netbeans.modules.openfile;

import java.awt.Component;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.InvalidDnDOperationException;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.openide.DialogDisplayer;
import org.openide.ErrorManager;
import org.openide.NotifyDescriptor;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.windows.ExternalDropHandler;
import org.openide.windows.TopComponent;

/**
 *
 * @author S. Aubrecht
 */
@org.openide.util.lookup.ServiceProvider(service=org.openide.windows.ExternalDropHandler.class, position = 1000)
public class DefaultExternalDropHandler extends ExternalDropHandler {
    
    private static final Logger LOG =
            Logger.getLogger(DefaultExternalDropHandler.class.getName());
    private static final RequestProcessor RP
            = new RequestProcessor(DefaultExternalDropHandler.class);

    public boolean canDrop(DropTargetDragEvent e) {
        return canDrop( e.getCurrentDataFlavors() );
    }

    public boolean canDrop(DropTargetDropEvent e) {
        return canDrop( e.getCurrentDataFlavors() );
    }

    boolean canDrop( DataFlavor[] flavors ) {
        for( int i=0; null != flavors && i fileList = getFileList( t );
        if ((fileList == null) || fileList.isEmpty()) {
            return false;
        }

        //#158473: Activate target TC to inform winsys in which mode new editor
        //component should be opened. It assumes that openFile opens new editor component
        //in some editor mode. If there would be problem with activating another TC first
        //then another way how to infrom winsys must be used.
        Component c = e.getDropTargetContext().getComponent();
        while (c != null) {
            if (c instanceof TopComponent) {
                ((TopComponent) c).requestActive();
                break;
            }
            c = c.getParent();
        }

        Object errMsg = null;
        if (fileList.size() == 1) {
            errMsg = openFile(fileList.get(0));
        } else {
            boolean hasSomeSuccess = false;
            List fileErrs = null;
            for (File file : fileList) {
                String fileErr = openFile(file);
                if (fileErr == null) {
                    hasSomeSuccess = true;
                } else {
                    if (fileErrs == null) {
                        fileErrs = new ArrayList(fileList.size());
                    }
                    fileErrs.add(fileErr);
                }
            }
            if (fileErrs != null) {         //some file could not be opened
                String mainMsgKey;
                if (hasSomeSuccess) {
                    mainMsgKey = "MSG_could_not_open_some_files";       //NOI18N
                } else {
                    mainMsgKey = "MSG_could_not_open_any_file";         //NOI18N
                }
                String mainMsg = NbBundle.getMessage(OpenFile.class, mainMsgKey);
                if (fileErrs == null) {
                    errMsg = mainMsg;
                } else {
                    JComponent msgPanel = new JPanel();
                    msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
                    msgPanel.add(new JLabel(mainMsg));
                    msgPanel.add(Box.createVerticalStrut(12));
                    for (String fileErr : fileErrs) {
                        msgPanel.add(new JLabel(fileErr));
                    }
                    errMsg = msgPanel;
                }
            }
        }
        if (errMsg != null) {
            showWarningMessageFileNotOpened(errMsg);
            return false;
        }
        return true;
    }

    static void showWarningMessageFileNotOpened(Object errMsg) {
        DialogDisplayer.getDefault().notify(
                new NotifyDescriptor.Message(
                        errMsg,
                        NotifyDescriptor.WARNING_MESSAGE));
    }

    List getFileList( Transferable t ) {
        try {
            if( t.isDataFlavorSupported( DataFlavor.javaFileListFlavor ) ) {
                //windows & mac
                try {
                    return (List) t.getTransferData(DataFlavor.javaFileListFlavor);
                } catch (InvalidDnDOperationException ex) { // #212390
                    LOG.log(Level.FINE, null, ex);
                }
            }
            if (t.isDataFlavorSupported(getUriListDataFlavor())) {
                //linux
                String uriList = (String)t.getTransferData( getUriListDataFlavor() );
                return textURIListToFileList( uriList );
            }
        } catch( UnsupportedFlavorException ex ) {
            ErrorManager.getDefault().notify( ErrorManager.INFORMATIONAL, ex );
        } catch( IOException ex ) {
            // Ignore. Can be just "Owner timed out" from sun.awt.X11.XSelection.getData.
            LOG.log(Level.FINE, null, ex);
        }
        return null;
    }

    /**
     * Opens the given file.
     *
     * If the file doesn't open in a reasonable time (2 seconds), let's assume
     * it will open successfully later (return null).
     *
     * @param  file  file to be opened
     * @return  {@code null} if the file was successfully opened;
     *          or a localized error message in case of failure
     */
    String openFile(final File file) {

        Callable task = new Callable() {
            @Override
            public String call() {
                File normalized = FileUtil.normalizeFile(file);
                FileObject fo = FileUtil.toFileObject(normalized);
                if (fo == null) {
                    return NbBundle.getMessage(OpenFile.class,
                            "MSG_FilePathTypeNotSupported", //NOI18N
                            file.toString());
                }
                return OpenFile.open(fo, -1);
            }
        };
        Future future = RP.submit(task);
        try {
            return future.get(2, TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            // It seems the file is still opening, let's assume it'll succeed.
            return null;
        } catch (InterruptedException e) {
            LOG.log(Level.WARNING, null, e);
            return null;
        } catch (ExecutionException e) {
            // Should not happen, error message string should be returned.
            LOG.log(Level.INFO, null, e);
            return null;
        }
    }

    private static DataFlavor uriListDataFlavor;

    DataFlavor getUriListDataFlavor() {
        if( null == uriListDataFlavor ) {
            try {
                uriListDataFlavor = new DataFlavor("text/uri-list;class=java.lang.String");
            } catch( ClassNotFoundException cnfE ) {
                //cannot happen
                throw new AssertionError(cnfE);
            }
        }
        return uriListDataFlavor;
    }

    List textURIListToFileList( String data ) {
        List list = new ArrayList(1);
        for( StringTokenizer st = new StringTokenizer(data, "\r\n\u0000");
            st.hasMoreTokens();) {
            String s = st.nextToken();
            if( s.startsWith("#") ) {
                // the line is a comment (as per the RFC 2483)
                continue;
            }
            try {
                URI uri = new URI(s);
                File file = new File(uri);
                list.add( file );
            } catch( java.net.URISyntaxException e ) {
                // malformed URI
            } catch( IllegalArgumentException e ) {
                // the URI is not a valid 'file:' URI
            }
        }
        return list;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy