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

org.eclipse.swt.program.Program Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2000, 2017 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.swt.program;

import java.io.*;
import java.nio.file.*;
import java.nio.file.Path;
import java.util.*;

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.gtk.*;
import org.eclipse.swt.internal.gtk3.*;
import org.eclipse.swt.internal.gtk4.*;

/**
 * Instances of this class represent programs and
 * their associated file extensions in the operating
 * system.
 *
 * @see Program snippets
 * @see Sample code and further information
 */
public final class Program {
	String name = ""; //$NON-NLS-1$
	String command;
	String iconPath;

	/* GIO specific
	 * true if command expects a URI
	 * false if expects a path
	 */
	boolean gioExpectUri;

	static long modTime;
	static Map> mimeTable;

	static final String PREFIX_HTTP = "http://"; //$NON-NLS-1$
	static final String PREFIX_HTTPS = "https://"; //$NON-NLS-1$

/**
 * Prevents uninitialized instances from being created outside the package.
 */
Program() {
}

static String[] parseCommand(String cmd) {
	List args = new ArrayList<>();
	int sIndex = 0;
	int eIndex;
	while (sIndex < cmd.length()) {
		/* Trim initial white space of argument. */
		while (sIndex < cmd.length() && Character.isWhitespace(cmd.charAt(sIndex))) {
			sIndex++;
		}
		if (sIndex < cmd.length()) {
			/* If the command is a quoted string */
			if (cmd.charAt(sIndex) == '"' || cmd.charAt(sIndex) == '\'') {
				/* Find the terminating quote (or end of line).
				 * This code currently does not handle escaped characters (e.g., " a\"b").
				 */
				eIndex = sIndex + 1;
				while (eIndex < cmd.length() && cmd.charAt(eIndex) != cmd.charAt(sIndex)) eIndex++;
				if (eIndex >= cmd.length()) {
					/* The terminating quote was not found
					 * Add the argument as is with only one initial quote.
					 */
					args.add(cmd.substring(sIndex, eIndex));
				} else {
					/* Add the argument, trimming off the quotes. */
					args.add(cmd.substring(sIndex + 1, eIndex));
				}
				sIndex = eIndex + 1;
			}
			else {
				/* Use white space for the delimiters. */
				eIndex = sIndex;
				while (eIndex < cmd.length() && !Character.isWhitespace(cmd.charAt(eIndex))) eIndex++;
				args.add(cmd.substring(sIndex, eIndex));
				sIndex = eIndex + 1;
			}
		}
	}

	return args.toArray(new String[args.size()]);
}

/**
 * Finds the program that is associated with an extension.
 * The extension may or may not begin with a '.'.  Note that
 * a Display must already exist to guarantee that
 * this method returns an appropriate result.
 *
 * @param extension the program extension
 * @return the program or null
 *
 * @exception IllegalArgumentException 
    *
  • ERROR_NULL_ARGUMENT when extension is null
  • *
*/ public static Program findProgram(String extension) { if (extension == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (extension.length() == 0) return null; if (extension.charAt(0) != '.') extension = "." + extension; String mimeType = gio_getMimeType(extension); if (mimeType == null) return null; return gio_getProgram(mimeType); } /** * Returns the receiver's image data at 100% zoom level. * This is the icon that is associated with the receiver * in the operating system. * * @return the image data for the program, may be null */ public ImageData getImageData() { return getImageData(100); } /** * Returns the receiver's image data based on the given zoom level. * This is the icon that is associated with the receiver in the * operating system. * * @param zoom * The zoom level in % of the standard resolution * * @return the image data for the program, may be null * @since 3.125 */ public ImageData getImageData(int zoom) { if (iconPath == null) return null; ImageData data = null; long gicon = OS.g_icon_new_for_string(Converter.javaStringToCString(iconPath), null); if (gicon != 0) { long pixbuf = 0; if (GTK.GTK4) { /* * Specified size will not be respected as in order to get the pixbuf, * we get the original image file which could be any size. Also, note * that gtk_icon_theme_lookup_by_gicon never returns NULL, it will * return a error icon if gicon can't be found. */ long icon_theme = GTK4.gtk_icon_theme_get_for_display(GDK.gdk_display_get_default()); // default display needs to exist long paintable = GTK4.gtk_icon_theme_lookup_by_gicon(icon_theme, gicon, 16, 1, GTK.GTK_TEXT_DIR_NONE, GTK.GTK_ICON_LOOKUP_FORCE_REGULAR); long file = GTK4.gtk_icon_paintable_get_file(paintable); long texture = GDK.gdk_texture_new_from_file(file, 0); pixbuf = GDK.gdk_pixbuf_get_from_texture(texture); OS.g_object_unref(texture); OS.g_object_unref(file); OS.g_object_unref(paintable); } else { long icon_theme = GTK3.gtk_icon_theme_get_default(); long gicon_info = GTK3.gtk_icon_theme_lookup_by_gicon(icon_theme, gicon, 16/*size*/, 0); if (gicon_info != 0) { pixbuf = GTK3.gtk_icon_info_load_icon(gicon_info, null); OS.g_object_unref(gicon_info); } } // Unref gicon as we have retrieved the required pixbuf OS.g_object_unref(gicon); if (pixbuf != 0) { int stride = GDK.gdk_pixbuf_get_rowstride(pixbuf); long pixels = GDK.gdk_pixbuf_get_pixels(pixbuf); int height = GDK.gdk_pixbuf_get_height(pixbuf); int width = GDK.gdk_pixbuf_get_width(pixbuf); boolean hasAlpha = GDK.gdk_pixbuf_get_has_alpha(pixbuf); // Move pixbuf memory to srcData and unref pixbuf byte[] srcData = new byte[stride * height]; C.memmove(srcData, pixels, srcData.length); OS.g_object_unref(pixbuf); if (hasAlpha) { PaletteData palette = new PaletteData(0xFF000000, 0xFF0000, 0xFF00); data = new ImageData(width, height, 32, palette, 4, srcData); data.bytesPerLine = stride; int s = 3, a = 0; byte[] alphaData = new byte[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { alphaData[a++] = srcData[s]; srcData[s] = 0; s+=4; } } data.alphaData = alphaData; } else { PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF); data = new ImageData(width, height, 24, palette, 4, srcData); data.bytesPerLine = stride; } } } return data; } static Map> gio_getMimeInfo() { /* * The file 'globs' contain the file extensions associated to the * mime-types. Each line that has to be parsed corresponds to a * different extension of a mime-type. The template of such line is - * application/pdf:*.pdf */ Path path = Paths.get("/usr/share/mime/globs"); long lastModified = 0; try { lastModified = Files.getLastModifiedTime(path).toMillis(); } catch (IOException e) { // ignore and reparse the file } if (modTime != 0 && modTime == lastModified) { return mimeTable; } else { try { mimeTable = new HashMap<>(); modTime = lastModified; for (String line : Files.readAllLines(path)) { int separatorIndex = line.indexOf(':'); if (separatorIndex > 0) { List mimeTypes = new ArrayList<>(); String mimeType = line.substring(0, separatorIndex); String extensionFormat = line.substring(separatorIndex + 1); int extensionIndex = extensionFormat.indexOf('.'); if (extensionIndex > 0) { String extension = extensionFormat.substring(extensionIndex); if (mimeTable.containsKey(extension)) { /* * If mimeType already exists, it is required to * update the existing key (mime-type) with the * new extension. */ List value = mimeTable.get(extension); mimeTypes.addAll(value); } mimeTypes.add(mimeType); mimeTable.put(extension, mimeTypes); } } } return mimeTable; } catch (IOException e) { } } return null; } static String gio_getMimeType(String extension) { String mimeType = null; Map> h = gio_getMimeInfo(); if (h != null && h.containsKey(extension)) { List mimeTypes = h.get(extension); mimeType = mimeTypes.get(0); } return mimeType; } static Program gio_getProgram(String mimeType) { Program program = null; byte[] mimeTypeBuffer = Converter.wcsToMbcs (mimeType, true); long application = OS.g_app_info_get_default_for_type (mimeTypeBuffer, false); if (application != 0) { program = gio_getProgram(application); } return program; } static Program gio_getProgram (long application) { Program program = new Program(); int length; byte[] buffer; long applicationName = OS.g_app_info_get_name (application); if (applicationName != 0) { length = C.strlen (applicationName); if (length > 0) { buffer = new byte [length]; C.memmove (buffer, applicationName, length); program.name = new String (Converter.mbcsToWcs (buffer)); } } long applicationCommand = OS.g_app_info_get_executable (application); if (applicationCommand != 0) { length = C.strlen (applicationCommand); if (length > 0) { buffer = new byte [length]; C.memmove (buffer, applicationCommand, length); program.command = new String (Converter.mbcsToWcs (buffer)); } } program.gioExpectUri = OS.g_app_info_supports_uris(application); long icon = OS.g_app_info_get_icon(application); if (icon != 0) { long icon_name = OS.g_icon_to_string(icon); if (icon_name != 0) { length = C.strlen(icon_name); if (length > 0) { buffer = new byte[length]; C.memmove(buffer, icon_name, length); program.iconPath = new String(Converter.mbcsToWcs(buffer)); } OS.g_free(icon_name); } } return program.command != null ? program : null; } /** * Answers all available programs in the operating system. Note * that a Display must already exist to guarantee * that this method returns an appropriate result. * * @return an array of programs */ public static Program[] getPrograms() { long applicationList = OS.g_app_info_get_all (); long list = applicationList; Program program; LinkedHashSet programs = new LinkedHashSet<>(); while (list != 0) { long application = OS.g_list_data(list); if (application != 0) { //TODO: Should the list be filtered or not? // if (OS.g_app_info_should_show(application)) { program = gio_getProgram(application); if (program != null) programs.add(program); // } OS.g_object_unref(application); } list = OS.g_list_next(list); } if (applicationList != 0) OS.g_list_free(applicationList); return programs.toArray(new Program[programs.size()]); } static boolean isExecutable(String fileName) { byte[] fileNameBuffer = Converter.wcsToMbcs (fileName, true); if (OS.g_file_test(fileNameBuffer, OS.G_FILE_TEST_IS_DIR)) return false; if (!OS.g_file_test(fileNameBuffer, OS.G_FILE_TEST_IS_EXECUTABLE)) return false; long file = OS.g_file_new_for_path (fileNameBuffer); boolean result = false; if (file != 0) { byte[] buffer = Converter.wcsToMbcs ("*", true); //$NON-NLS-1$ long fileInfo = OS.g_file_query_info(file, buffer, 0, 0, 0); if (fileInfo != 0) { long contentType = OS.g_file_info_get_content_type(fileInfo); if (contentType != 0) { byte[] exeType = Converter.wcsToMbcs ("application/x-executable", true); //$NON-NLS-1$ result = OS.g_content_type_is_a(contentType, exeType); if (!result) { byte [] shellType = Converter.wcsToMbcs ("application/x-shellscript", true); //$NON-NLS-1$ result = OS.g_content_type_equals(contentType, shellType); } } OS.g_object_unref(fileInfo); } OS.g_object_unref (file); } return result; } /** * GIO - Launch the default program for the given file. */ static boolean gio_launch(String fileName) { boolean result = false; byte[] fileNameBuffer = Converter.wcsToMbcs (fileName, true); long file = OS.g_file_new_for_commandline_arg (fileNameBuffer); if (file != 0) { long uri = OS.g_file_get_uri (file); if (uri != 0) { result = OS.g_app_info_launch_default_for_uri (uri, 0, 0); OS.g_free(uri); } OS.g_object_unref (file); } return result; } /** * GIO - Execute the program for the given file. */ boolean gio_execute(String fileName) { boolean result = false; byte[] commandBuffer = Converter.wcsToMbcs (command, true); byte[] nameBuffer = Converter.wcsToMbcs (name, true); long application = OS.g_app_info_create_from_commandline(commandBuffer, nameBuffer, gioExpectUri ? OS.G_APP_INFO_CREATE_SUPPORTS_URIS : OS.G_APP_INFO_CREATE_NONE, 0); if (application != 0) { byte[] fileNameBuffer = Converter.wcsToMbcs (fileName, true); long file = 0; if (fileName.length() > 0) { if (OS.g_app_info_supports_uris (application)) { file = OS.g_file_new_for_uri (fileNameBuffer); } else { file = OS.g_file_new_for_path (fileNameBuffer); } } long list = 0; if (file != 0) list = OS.g_list_append (0, file); result = OS.g_app_info_launch (application, list, 0, 0); if (list != 0) { OS.g_list_free (list); OS.g_object_unref (file); } OS.g_object_unref (application); } return result; } /** * Answer all program extensions in the operating system. Note * that a Display must already exist to guarantee * that this method returns an appropriate result. * * @return an array of extensions */ public static String[] getExtensions() { Map> mimeInfo = gio_getMimeInfo(); if (mimeInfo == null) return new String[0]; /* Create a unique set of the file extensions. */ List extensions = new ArrayList<>(mimeInfo.keySet()); /* Return the list of extensions. */ return extensions.toArray(new String[extensions.size()]); } /** * Launches the operating system executable associated with the file or * URL (http:// or https://). If the file is an executable then the * executable is launched. Note that a Display must already * exist to guarantee that this method returns an appropriate result. * * @param fileName the file or program name or URL (http:// or https://) * @return true if the file is launched, otherwise false * * @exception IllegalArgumentException
    *
  • ERROR_NULL_ARGUMENT when fileName is null
  • *
*/ public static boolean launch(String fileName) { return launch(fileName, null); } /** * Launches the operating system executable associated with the file or * URL (http:// or https://). If the file is an executable then the * executable is launched. The program is launched with the specified * working directory only when the workingDir exists and * fileName is an executable. * Note that a Display must already exist to guarantee * that this method returns an appropriate result. * * @param fileName the file name or program name or URL (http:// or https://) * @param workingDir the name of the working directory or null * @return true if the file is launched, otherwise false * * @exception IllegalArgumentException
    *
  • ERROR_NULL_ARGUMENT when fileName is null
  • *
* * @since 3.6 */ public static boolean launch (String fileName, String workingDir) { if (fileName == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); if (workingDir != null && isExecutable(fileName)) { try { Compatibility.exec (new String [] {fileName}, null, workingDir); return true; } catch (IOException e) { return false; } } if (gio_launch (fileName)) return true; int index = fileName.lastIndexOf ('.'); if (index != -1) { String extension = fileName.substring (index); Program program = Program.findProgram (extension); if (program != null && program.execute (fileName)) return true; } String lowercaseName = fileName.toLowerCase (); if (lowercaseName.startsWith (PREFIX_HTTP) || lowercaseName.startsWith (PREFIX_HTTPS)) { Program program = Program.findProgram (".html"); //$NON-NLS-1$ if (program == null) { program = Program.findProgram (".htm"); //$NON-NLS-1$ } if (program != null && program.execute (fileName)) return true; } /* If the above launch attempts didn't launch the file, then try with exec().*/ try { Compatibility.exec (new String [] {fileName}, null, workingDir); return true; } catch (IOException e) { return false; } } /** * Compares the argument to the receiver, and returns true * if they represent the same object using a class * specific comparison. * * @param other the object to compare with this object * @return true if the object is the same as this object and false otherwise * * @see #hashCode() */ @Override public boolean equals(Object other) { if (this == other) return true; if (!(other instanceof Program)) return false; Program program = (Program)other; return name.equals(program.name) && command.equals(program.command) && gioExpectUri == program.gioExpectUri; } /** * Executes the program with the file as the single argument * in the operating system. It is the responsibility of the * programmer to ensure that the file contains valid data for * this program. * * @param fileName the file or program name * @return true if the file is launched, otherwise false * * @exception IllegalArgumentException
    *
  • ERROR_NULL_ARGUMENT when fileName is null
  • *
*/ public boolean execute(String fileName) { if (fileName == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); return gio_execute(fileName); } /** * Returns the receiver's name. This is as short and * descriptive a name as possible for the program. If * the program has no descriptive name, this string may * be the executable name, path or empty. * * @return the name of the program */ public String getName() { return name; } /** * Returns an integer hash code for the receiver. Any two * objects that return true when passed to * equals must return the same value for this * method. * * @return the receiver's hash * * @see #equals(Object) */ @Override public int hashCode() { return name.hashCode() ^ command.hashCode(); } /** * Returns a string containing a concise, human-readable * description of the receiver. * * @return a string representation of the program */ @Override public String toString() { return "Program {" + name + "}"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy