Java tutorial
/******************************************************************************* * Copyright (c) 2006-2008 VecTrace (Zingo Andersen) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VecTrace (Zingo Andersen) - implementation * Software Balm Consulting Inc (Peter Hunnisett <peter_hge at softwarebalm dot com>) - some updates * StefanC - some updates * Stefan Groschupf - logError * Bastian Doetsch - updates, cleanup and documentation * Andrei Loskutov - bug fixes *******************************************************************************/ package com.vectrace.MercurialEclipse.team; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.jobs.IJobManager; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.preference.PreferenceDialog; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.RGB; import org.eclipse.ui.dialogs.PreferencesUtil; import com.vectrace.MercurialEclipse.MercurialEclipsePlugin; import com.vectrace.MercurialEclipse.SafeUiJob; import com.vectrace.MercurialEclipse.commands.AbstractClient; import com.vectrace.MercurialEclipse.commands.HgClients; import com.vectrace.MercurialEclipse.commands.HgConfigClient; import com.vectrace.MercurialEclipse.commands.HgLogClient; import com.vectrace.MercurialEclipse.exception.HgException; import com.vectrace.MercurialEclipse.model.ChangeSet; import com.vectrace.MercurialEclipse.model.FileStatus; import com.vectrace.MercurialEclipse.model.HgFile; import com.vectrace.MercurialEclipse.model.HgRoot; import com.vectrace.MercurialEclipse.model.JHgChangeSet; import com.vectrace.MercurialEclipse.model.NullHgFile; import com.vectrace.MercurialEclipse.preferences.MercurialPreferenceConstants; import com.vectrace.MercurialEclipse.storage.HgCommitMessageManager; import com.vectrace.MercurialEclipse.team.cache.LocalChangesetCache; import com.vectrace.MercurialEclipse.utils.IniFile; import com.vectrace.MercurialEclipse.utils.StringUtils; /** * Class that offers Utility methods for working with the plug-in. * * @author zingo * */ public final class MercurialUtilities { private static final boolean IS_WINDOWS = File.separatorChar == '\\'; private static final Map<RGB, Color> COLOR_MAP = new HashMap<RGB, Color>(); private static final Map<FontData, Font> FONT_MAP = new HashMap<FontData, Font>(); /** * This class is full of utilities metods, useful allover the place */ private MercurialUtilities() { // don't call me } public static boolean isWindows() { return IS_WINDOWS; } /** * Determines if the configured Mercurial executable can be called. * * @return true if no error occurred while calling the executable, false otherwise */ public static boolean isHgExecutableCallable() { try { exec(getHGExecutable()); return true; } catch (IOException e) { return false; } } private static void exec(String exec) throws IOException { //Runtime.getRuntime().exec(getHGExecutable()); new ProcessBuilder(exec).start(); } /** * Returns the hg executable stored in the plug-in preferences. If it's not defined, "hg" is * returned as default. * * @return the path to the executable or, if not defined "hg" * @deprecated Use {@link com.vectrace.MercurialEclipse.commands.HgClients#getExecutable()} */ @Deprecated public static String getHGExecutable() { return HgClients.getPreference(MercurialPreferenceConstants.MERCURIAL_EXECUTABLE, "hg"); //$NON-NLS-1$ } /** * Fetches a preference from the plug-in's preference store. If no preference could be found in * the store, the given default is returned. * * @param preferenceConstant * the string identifier for the constant. * @param defaultIfNotSet * the default to return if no preference was found. * @return the preference or the default */ public static String getPreference(String preferenceConstant, String defaultIfNotSet) { IPreferenceStore preferenceStore = MercurialEclipsePlugin.getDefault().getPreferenceStore(); // This returns "" if not defined String pref = preferenceStore.getString(preferenceConstant); if (pref.length() > 0) { return pref; } return defaultIfNotSet; } /** * Gets the configured executable if it's callable (@see * {@link MercurialUtilities#isHgExecutableCallable()}. * * If configureIfMissing is set to true, the configuration will be started and afterwards the * executable stored in the preferences will be checked if it is callable. If true, it is * returned, else "hg" will be returned. If the parameter is set to false, it will returns "hg" * if no preference is set. * * @param configureIfMissing * flag if configuration should be started if hg is not callable. * @return the hg executable path */ public static String getHGExecutable(boolean configureIfMissing) { if (isHgExecutableCallable()) { return getHGExecutable(); } if (configureIfMissing) { configureHgExecutable(); return getHGExecutable(); } return "hg"; //$NON-NLS-1$ } /** * Checks the GPG Executable is callable and returns it if it is. * * Otherwise, if configureIfMissing is set to true, configuration will be started and the new * command is tested for callability. If there's no preference found after configuration, "gpg" * will be returned as default. * * @param configureIfMissing * flag, if configuration should be started if gpg is not callable. * @return the gpg executable path */ public static String getGpgExecutable(boolean configureIfMissing) { if (isGpgExecutableCallable()) { return getGpgExecutable(); } if (configureIfMissing) { configureGpgExecutable(); return getGpgExecutable(); } return "gpg"; //$NON-NLS-1$ } /** * Starts configuration for Gpg executable by opening the preference page. */ public static void configureGpgExecutable() { configureHgExecutable(); } private static boolean isGpgExecutableCallable() { try { exec(getGpgExecutable()); return true; } catch (Exception e) { return false; } } /** * Returns the executable for gpg. If it's not defined, false is returned * * @return gpg executable path or "gpg", if it's not set. */ public static String getGpgExecutable() { String executable = HgClients.getPreference(MercurialPreferenceConstants.GPG_EXECUTABLE, "gpg"); //$NON-NLS-1$ if (executable == null || executable.length() == 0) { return "false"; //$NON-NLS-1$ } return executable; } /** * Starts the configuration for Mercurial executable by opening the preference page. */ public static void configureHgExecutable() { final String jobName = Messages .getString("MercurialUtilities.openingPreferencesForConfiguringMercurialEclipse"); SafeUiJob job = new SafeUiJob(jobName) { @Override protected IStatus runSafe(IProgressMonitor monitor) { String pageId = "com.vectrace.MercurialEclipse.prefspage"; //$NON-NLS-1$ PreferenceDialog dlg = PreferencesUtil.createPreferenceDialogOn(getDisplay().getActiveShell(), pageId, null, null); dlg.setErrorMessage(Messages.getString("MercurialUtilities.errorNotConfiguredCorrectly") //$NON-NLS-1$ + Messages.getString("MercurialUtilities.runDebugInstall")); //$NON-NLS-1$ dlg.open(); return super.runSafe(monitor); } @Override public boolean belongsTo(Object family) { return jobName.equals(family); } }; IJobManager jobManager = Job.getJobManager(); jobManager.cancel(jobName); Job[] jobs = jobManager.find(jobName); if (jobs.length == 0) { job.schedule(50); } } /** * Get the user name trimmed to null. If user is not provided uses the default username * @see #getDefaultUserName() * @param user The user to prefer * @return The user name, may be null. */ public static String getDefaultUserName(String user) { user = user != null ? user : getDefaultUserName(); if (user != null) { user = user.trim(); if (user.length() == 0) { user = null; } } return user; } /** * Returns the username for hg as configured in preferences. If it's not defined in the * preference store, null is returned. * <p> * <b>Note:</b> Preferred way to access user commit name is to use * {@link HgCommitMessageManager#getDefaultCommitName(HgRoot)} * * @return hg username or empty string, never null */ public static String getDefaultUserName() { IPreferenceStore preferenceStore = MercurialEclipsePlugin.getDefault().getPreferenceStore(); // This returns "" if not defined String username = preferenceStore.getString(MercurialPreferenceConstants.MERCURIAL_USERNAME); // try to read username via hg showconfig if (StringUtils.isEmpty(username)) { try { username = HgConfigClient.getHgConfigLine("ui.username"); } catch (HgException e) { MercurialEclipsePlugin.logError(e); } } // try to read mercurial hgrc in default locations String home = System.getProperty("user.home"); if (StringUtils.isEmpty(username)) { username = readUsernameFromIni(home + "/.hgrc"); } if (isWindows()) { if (StringUtils.isEmpty(username)) { username = readUsernameFromIni(home + "/Mercurial.ini"); } if (StringUtils.isEmpty(username)) { username = readUsernameFromIni("C:/Mercurial/Mercurial.ini"); } } if (StringUtils.isEmpty(username)) { // use system username username = System.getProperty("user.name"); } // never return null! if (username == null) { username = ""; } return username; } private static String readUsernameFromIni(String filename) { String username; try { IniFile iniFile = new IniFile(filename); username = iniFile.getKeyValue("ui", "username"); } catch (FileNotFoundException e) { username = null; } return username; } public static boolean isCommandAvailable(String command, QualifiedName sessionPropertyName, String extensionEnabler) throws HgException { try { boolean returnValue; IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); Object prop = workspaceRoot.getSessionProperty(sessionPropertyName); if (prop != null) { returnValue = ((Boolean) prop).booleanValue(); } else { returnValue = AbstractClient.isCommandAvailable(command, extensionEnabler); workspaceRoot.setSessionProperty(sessionPropertyName, Boolean.valueOf(returnValue)); } return returnValue; } catch (CoreException e) { throw new HgException(e); } } public static Color getColorPreference(String pref) { RGB rgb = PreferenceConverter.getColor(MercurialEclipsePlugin.getDefault().getPreferenceStore(), pref); return getColor(rgb); } public static Color getColor(RGB rgb) { Color color; synchronized (COLOR_MAP) { color = COLOR_MAP.get(rgb); if (color == null) { color = new Color(MercurialEclipsePlugin.getStandardDisplay(), rgb); COLOR_MAP.put(rgb, color); } } return color; } public static void disposeColorsAndFonts() { for (Color c : COLOR_MAP.values()) { c.dispose(); } COLOR_MAP.clear(); for (Font f : FONT_MAP.values()) { f.dispose(); } FONT_MAP.clear(); } public static Font getFont(FontData data) { Font font; synchronized (FONT_MAP) { font = FONT_MAP.get(data); if (font == null) { font = new Font(MercurialEclipsePlugin.getStandardDisplay(), data); FONT_MAP.put(data, font); } } return font; } public static Font getFontPreference(String pref) { FontData data = PreferenceConverter.getFontData(MercurialEclipsePlugin.getDefault().getPreferenceStore(), pref); return getFont(data); } /** * Get the parent revision. Is aware of file renames. * * Note: May query and update the file status of cs. * * @param cs The changeset in which the file was modified * @param file The file as of cs's revision * @return Storage for the parent revision * @throws HgException */ public static HgFile getParentRevision(ChangeSet cs, IFile file) throws HgException { return getParentRevision(cs, cs.getHgRoot().getRelativePath(file)); } /** * Get the parent revision. Is aware of file renames. * * Note: May query and update the file status of cs. * * @param cs The changeset in which the file was modified * @param path The path as of cs's revision * @return Storage for the parent revision * @throws HgException */ public static HgFile getParentRevision(ChangeSet cs, IPath path) throws HgException { String[] parents = cs.getParents(); if (cs.getIndex() == 0) { return new NullHgFile(cs.getHgRoot(), cs.getNode(), path); } else if (parents.length == 0) { throw new IllegalStateException(); } FileStatus stat = cs.getStatus(path); if (stat != null && stat.isCopied()) { path = stat.getAbsoluteCopySourcePath(); } JHgChangeSet parentCs; if (cs.getBundleFile() == null) { parentCs = LocalChangesetCache.getInstance().get(cs.getHgRoot(), parents[0]); } else { // TODO: from cache? parentCs = HgLogClient.getChangeSet(cs.getHgRoot(), parents[0], cs.getRepository(), cs.getDirection(), cs.getBundleFile()); } return HgFile.locate(parentCs, path); } public static void setOfferAutoCommitMerge(boolean offer) { try { ResourcesPlugin.getWorkspace().getRoot().setSessionProperty(ResourceProperties.MERGE_COMMIT_OFFERED, (offer ? null : "true")); } catch (CoreException e) { MercurialEclipsePlugin.logError(e); } } public static boolean isOfferAutoCommitMerge() { try { return ResourcesPlugin.getWorkspace().getRoot() .getSessionProperty(ResourceProperties.MERGE_COMMIT_OFFERED) == null; } catch (CoreException e) { MercurialEclipsePlugin.logError(e); return true; } } }