Mercurial > projects > dwt-mac
diff dwt/program/Program.d @ 45:d8635bb48c7c
Merge with SWT 3.5
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Mon, 01 Dec 2008 17:07:00 +0100 |
parents | a9ab4c738ed8 |
children | cfa563df4fdd |
line wrap: on
line diff
--- a/dwt/program/Program.d Tue Oct 21 15:20:04 2008 +0200 +++ b/dwt/program/Program.d Mon Dec 01 17:07:00 2008 +0100 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation 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 @@ -13,25 +13,49 @@ import dwt.dwthelper.utils; +import java.util.Vector; + import dwt.DWT; import dwt.graphics.ImageData; +import dwt.graphics.PaletteData; +import dwt.internal.C; +import dwt.internal.cocoa.NSArray; +import dwt.internal.cocoa.NSAutoreleasePool; +import dwt.internal.cocoa.NSBitmapImageRep; +import dwt.internal.cocoa.NSBundle; +import dwt.internal.cocoa.NSDictionary; +import dwt.internal.cocoa.NSDirectoryEnumerator; +import dwt.internal.cocoa.NSEnumerator; +import dwt.internal.cocoa.NSFileManager; +import dwt.internal.cocoa.NSImage; +import dwt.internal.cocoa.NSImageRep; +import dwt.internal.cocoa.NSMutableSet; +import dwt.internal.cocoa.NSSize; import dwt.internal.cocoa.NSString; import dwt.internal.cocoa.NSURL; import dwt.internal.cocoa.NSWorkspace; +import dwt.internal.cocoa.OS; +import dwt.internal.cocoa.id; /** * Instances of this class represent programs and * their associated file extensions in the operating * system. + * + * @see <a href="http://www.eclipse.org/swt/snippets/#program">Program snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> */ public final class Program { - String name; - byte[] fsRef; + String name, fullPath, identifier; + + static final String PREFIX_FILE = "file://"; //$NON-NLS-1$ + 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. */ -this () { +Program () { } /** @@ -50,25 +74,32 @@ public static Program findProgram (String extension) { if (extension is null) DWT.error (DWT.ERROR_NULL_ARGUMENT); if (extension.length () is 0) return null; -// char[] chars; -// if (extension.charAt (0) !is '.') { -// chars = new char[extension.length()]; -// extension.getChars(0, chars.length, chars, 0); -// } else { -// chars = new char[extension.length() - 1]; -// extension.getChars(1, extension.length(), chars, 0); -// } -// int ext = OS.CFStringCreateWithCharacters(OS.kCFAllocatorDefault, chars, chars.length); -// Program program = null; -// if (ext !is 0) { -// byte[] fsRef = new byte[80]; -// if (OS.LSGetApplicationForInfo(OS.kLSUnknownType, OS.kLSUnknownCreator, ext, OS.kLSRolesAll, fsRef, null) is OS.noErr) { -// program = getProgram(fsRef); -// } -// OS.CFRelease(ext); -// } -// return program; - return null; + if (extension.charAt(0) !is '.') extension = "." + extension; + NSAutoreleasePool pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + NSWorkspace workspace = NSWorkspace.sharedWorkspace(); + int /*long*/ appName = OS.malloc(C.PTR_SIZEOF); + int /*long*/ type = OS.malloc(C.PTR_SIZEOF); + NSString temp = new NSString(OS.NSTemporaryDirectory()); + NSString fileName = NSString.stringWith("swt" + System.currentTimeMillis() + extension); + NSString fullPath = temp.stringByAppendingPathComponent(fileName); + NSFileManager fileManager = NSFileManager.defaultManager(); + fileManager.createFileAtPath(fullPath, null, null); + workspace.getInfoForFile(fullPath, appName, type); + fileManager.removeItemAtPath(fullPath, 0); + int /*long*/ [] buffer = new int /*long*/[1]; + OS.memmove(buffer, appName, C.PTR_SIZEOF); + OS.free(appName); + OS.free(type); + if (buffer [0] !is 0) { + NSString appPath = new NSString(buffer[0]); + NSBundle bundle = NSBundle.bundleWithPath(appPath); + if (bundle !is null) return getProgram(bundle); + } + return null; + } finally { + pool.release(); + } } /** @@ -79,199 +110,79 @@ * @return an array of extensions */ public static String [] getExtensions () { - return new String [] { - // From System-Declared Uniform Type Identifiers - ".txt", - ".rtf", - ".html", - ".htm", - ".xml", - ".c", - ".m", - ".cp", ".cpp", ".c++", ".cc", ".cxx", - ".mm", - ".h", - ".hpp", - ".h++", - ".hxx", - ".java", - ".jav", - ".s", - ".r", - ".defs", - ".mig", - ".exp", - ".js", - ".jscript", - ".javascript", - ".sh", - ".command", - ".csh", - ".pl", - ".pm", - ".py", - ".rb", - ".rbw", - ".php", - ".php3", - ".php4", - ".ph3", - ".ph4", - ".phtml", - ".jnlp", - ".applescript", - ".scpt", - ".o", - ".exe", - ".dll", - ".class", - ".jar", - ".qtz", - ".gtar", - ".tar", - ".gz", - ".gzip", - ".tgz", - ".hqx", - ".bin", - ".vcf", - ".vcard", - ".jpg", - ".jpeg", - ".jp2", - ".tif", - ".tiff", - ".pic", - ".pct", - ".pict", - ".pntg", - ".png", - ".xbm", - ".qif", - ".qtif", - ".icns", - ".mov", - ".qt", - ".avi", - ".vfw", - ".mpg", - ".mpeg", - ".m75", - ".m15", - ".mp4", - ".3gp", - ".3gpp", - ".3g2", - ".3gp2", - ".mp3", - ".m4a", - ".m4p", - ".m4b", - ".au", - ".ulw", - ".snd", - ".aifc", - ".aiff", - ".aif", - ".caf", - ".bundle", - ".app", - ".plugin", - ".mdimporter", - ".wdgt", - ".cpio", - ".zip", - ".framework", - ".rtfd", - ".dfont", - ".otf", - ".ttf", - ".ttc", - ".suit", - ".pfb", - ".pfa", - ".icc", - ".icm", - ".pf", - ".pdf", - ".ps", - ".eps", - ".psd", - ".ai", - ".gif", - ".bmp", - ".ico", - ".doc", - ".xls", - ".ppt", - ".wav", - ".wave", - ".asf", - ".wm", - ".wmv", - ".wmp", - ".wma", - ".asx", - ".wmx", - ".wvx", - ".wax", - ".key", - ".kth", - ".tga", - ".sgi", - ".exr", - ".fpx", - ".jfx", - ".efx", - ".sd2", - ".rm", - ".ram", - ".ra", - ".smil", - ".sit", - ".sitx", - // Others - ".plist", - ".nib", - ".lproj", - // iChat - ".iPhoto", - // iChat - ".iChat", - ".chat", - // acrobat reader - ".rmf", - ".xfdf", - ".fdf", - // Chess - ".game", - ".pgn", - // iCal - ".ics", - ".vcs", - ".aplmodel", - ".icbu", - ".icalevent", - ".icaltodo", - // Mail - ".mailhold", - ".mbox", - ".imapmbox", - ".emlx", - ".mailextract", - // Sherlock - ".sherlock", - // Stickies - ".tpl", - // System Preferences - ".prefPane", - ".sliderSaver", - ".saver", - // Console - ".log", - // Grapher - ".gcx", - }; + NSAutoreleasePool pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + NSMutableSet supportedDocumentTypes = (NSMutableSet)NSMutableSet.set(); + NSWorkspace workspace = NSWorkspace.sharedWorkspace(); + NSString CFBundleDocumentTypes = NSString.stringWith("CFBundleDocumentTypes"); + NSString CFBundleTypeExtensions = NSString.stringWith("CFBundleTypeExtensions"); + NSArray array = new NSArray(OS.NSSearchPathForDirectoriesInDomains(OS.NSAllApplicationsDirectory, OS.NSAllDomainsMask, true)); + int count = (int)/*64*/array.count(); + for (int i = 0; i < count; i++) { + NSString path = new NSString(array.objectAtIndex(i)); + NSFileManager fileManager = NSFileManager.defaultManager(); + NSDirectoryEnumerator enumerator = fileManager.enumeratorAtPath(path); + if (enumerator !is null) { + id id; + while ((id = enumerator.nextObject()) !is null) { + enumerator.skipDescendents(); + NSString filePath = new NSString(id.id); + NSString fullPath = path.stringByAppendingPathComponent(filePath); + if (workspace.isFilePackageAtPath(fullPath)) { + NSBundle bundle = NSBundle.bundleWithPath(fullPath); + id = bundle.infoDictionary().objectForKey(CFBundleDocumentTypes); + if (id !is null) { + NSDictionary documentTypes = new NSDictionary(id.id); + NSEnumerator documentTypesEnumerator = documentTypes.objectEnumerator(); + while ((id = documentTypesEnumerator.nextObject()) !is null) { + NSDictionary documentType = new NSDictionary(id.id); + id = documentType.objectForKey(CFBundleTypeExtensions); + if (id !is null) { + supportedDocumentTypes.addObjectsFromArray(new NSArray(id.id)); + } + } + } + } + } + } + } + int i = 0; + String[] exts = new String[(int)/*64*/supportedDocumentTypes.count()]; + NSEnumerator enumerator = supportedDocumentTypes.objectEnumerator(); + id id; + while ((id = enumerator.nextObject()) !is null) { + String ext = new NSString(id.id).getString(); + if (!ext.equals("*")) exts[i++] = "." + ext; + } + if (i !is exts.length) { + String[] temp = new String[i]; + System.arraycopy(exts, 0, temp, 0, i); + exts = temp; + } + return exts; + } finally { + pool.release(); + } +} + +static Program getProgram(NSBundle bundle) { + NSString CFBundleName = NSString.stringWith("CFBundleName"); + NSString CFBundleDisplayName = NSString.stringWith("CFBundleDisplayName"); + NSString fullPath = bundle.bundlePath(); + NSString identifier = bundle.bundleIdentifier(); + id bundleName = bundle.objectForInfoDictionaryKey(CFBundleDisplayName); + if (bundleName is null) { + bundleName = bundle.objectForInfoDictionaryKey(CFBundleName); + } + if (bundleName is null) { + bundleName = fullPath.lastPathComponent().stringByDeletingPathExtension(); + } + NSString name = new NSString(bundleName.id); + Program program = new Program(); + program.name = name.getString(); + program.fullPath = fullPath.getString(); + program.identifier = identifier !is null ? identifier.getString() : ""; + return program; } /** @@ -282,72 +193,43 @@ * @return an array of programs */ public static Program [] getPrograms () { - return new Program[0]; -// Hashtable bundles = new Hashtable(); -// String[] extensions = getExtensions(); -// byte[] fsRef = new byte[80]; -// for (int i = 0; i < extensions.length; i++) { -// String extension = extensions[i]; -// char[] chars = new char[extension.length() - 1]; -// extension.getChars(1, extension.length(), chars, 0); -// int ext = OS.CFStringCreateWithCharacters(OS.kCFAllocatorDefault, chars, chars.length); -// if (ext !is 0) { -// if (OS.LSGetApplicationForInfo(OS.kLSUnknownType, OS.kLSUnknownCreator, ext, OS.kLSRolesAll, fsRef, null) is OS.noErr) { -// Program program = getProgram(fsRef); -// if (program !is null && bundles.get(program.getName()) is null) { -// bundles.put(program.getName(), program); -// fsRef = new byte[80]; -// } -// } -// if (OS.VERSION >= 0x1040) { -// int utis = OS.UTTypeCreateAllIdentifiersForTag(OS.kUTTagClassFilenameExtension(), ext, 0); -// if (utis !is 0) { -// int utiCount = OS.CFArrayGetCount(utis); -// for (int j = 0; j < utiCount; j++) { -// int uti = OS.CFArrayGetValueAtIndex(utis, j); -// if (uti !is 0) { -// int apps = OS.LSCopyAllRoleHandlersForContentType(uti, OS.kLSRolesAll); -// if (apps !is 0) { -// int appCount = OS.CFArrayGetCount(apps); -// for (int k = 0; k < appCount; k++) { -// int app = OS.CFArrayGetValueAtIndex(apps, k); -// if (app !is 0) {; -// if (OS.LSFindApplicationForInfo(OS.kLSUnknownCreator, app, 0, fsRef, null) is OS.noErr) { -// Program program = getProgram(fsRef); -// if (program !is null && bundles.get(program.getName()) is null) { -// bundles.put(program.getName(), program); -// fsRef = new byte[80]; -// } -// } -// } -// } -// OS.CFRelease(apps); -// } -// } -// } -// OS.CFRelease(utis); -// } -// } -// OS.CFRelease(ext); -// } -// } -// int count = 0; -// Program[] programs = new Program[bundles.size()]; -// Enumeration values = bundles.elements(); -// while (values.hasMoreElements()) { -// programs[count++] = cast(Program)values.nextElement(); -// } -// return programs; + NSAutoreleasePool pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + Vector vector = new Vector(); + NSWorkspace workspace = NSWorkspace.sharedWorkspace(); + NSArray array = new NSArray(OS.NSSearchPathForDirectoriesInDomains(OS.NSAllApplicationsDirectory, OS.NSAllDomainsMask, true)); + int count = (int)/*64*/array.count(); + for (int i = 0; i < count; i++) { + NSString path = new NSString(array.objectAtIndex(i)); + NSFileManager fileManager = NSFileManager.defaultManager(); + NSDirectoryEnumerator enumerator = fileManager.enumeratorAtPath(path); + if (enumerator !is null) { + id id; + while ((id = enumerator.nextObject()) !is null) { + enumerator.skipDescendents(); + NSString fullPath = path.stringByAppendingPathComponent(new NSString(id.id)); + if (workspace.isFilePackageAtPath(fullPath)) { + NSBundle bundle = NSBundle.bundleWithPath(fullPath); + vector.addElement(getProgram(bundle)); + } + } + } + } + Program[] programs = new Program[vector.size()]; + vector.copyInto(programs); + return programs; + } finally { + pool.release(); + } } /** - * Launches the executable associated with the file in - * the operating system. If the file is an executable, - * then the executable is launched. Note that a <code>Display</code> - * must already exist to guarantee that this method returns - * an appropriate result. + * 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 <code>Display</code> must already + * exist to guarantee that this method returns an appropriate result. * - * @param fileName the file or program name + * @param fileName the file or program name or URL (http:// or https://) * @return <code>true</code> if the file is launched, otherwise <code>false</code> * * @exception IllegalArgumentException <ul> @@ -356,9 +238,27 @@ */ public static bool launch (String fileName) { if (fileName is null) DWT.error (DWT.ERROR_NULL_ARGUMENT); - if (fileName.indexOf(':') is -1) fileName = "file://" + fileName; - NSWorkspace workspace = NSWorkspace.sharedWorkspace(); - return workspace.openURL(NSURL.static_URLWithString_(NSString.stringWith(fileName))); + NSAutoreleasePool pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + NSString unescapedStr = NSString.stringWith("%"); //$NON-NLS-1$ + if (fileName.indexOf(':') is -1) { + fileName = PREFIX_FILE + fileName; + } else { + String lowercaseName = fileName.toLowerCase (); + if (lowercaseName.startsWith (PREFIX_HTTP) || lowercaseName.startsWith (PREFIX_HTTPS)) { + unescapedStr = NSString.stringWith("%#"); //$NON-NLS-1$ + } + } + NSString fullPath = NSString.stringWith(fileName); + int /*long*/ ptr = OS.CFURLCreateStringByAddingPercentEscapes(0, fullPath.id, unescapedStr.id, 0, OS.kCFStringEncodingUTF8); + NSString escapedString = new NSString(ptr); + NSWorkspace workspace = NSWorkspace.sharedWorkspace(); + bool result = workspace.openURL(NSURL.URLWithString(escapedString)); + OS.CFRelease(ptr); + return result; + } finally { + pool.release(); + } } /** @@ -376,45 +276,26 @@ */ public bool execute (String fileName) { if (fileName is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); -// if (OS.VERSION < 0x1040) return launch(fileName); -// int rc = -1; -// int fsRefPtr = OS.NewPtr(fsRef.length); -// if (fsRefPtr !is 0) { -// OS.memmove(fsRefPtr, fsRef, fsRef.length); -// LSApplicationParameters params = new LSApplicationParameters(); -// params.version = 0; -// params.flags = 0; -// params.application = fsRefPtr; -// if (fileName.length() is 0) { -// rc = OS.LSOpenApplication(params, null); -// } else { -// if (fileName.indexOf(':') is -1) fileName = "file://" + fileName; -// char[] chars = new char[fileName.length()]; -// fileName.getChars(0, chars.length, chars, 0); -// int str = OS.CFStringCreateWithCharacters(0, chars, chars.length); -// if (str !is 0) { -// int unscapedStr = OS.CFStringCreateWithCharacters(0, new char[]{'%'}, 1); -// int escapedStr = OS.CFURLCreateStringByAddingPercentEscapes(OS.kCFAllocatorDefault, str, unscapedStr, 0, OS.kCFStringEncodingUTF8); -// if (escapedStr !is 0) { -// int urls = OS.CFArrayCreateMutable(OS.kCFAllocatorDefault, 1, 0); -// if (urls !is 0) { -// int url = OS.CFURLCreateWithString(OS.kCFAllocatorDefault, escapedStr, 0); -// if (url !is 0) { -// OS.CFArrayAppendValue(urls, url); -// rc = OS.LSOpenURLsWithRole(urls, OS.kLSRolesAll, 0, params, null, 0); -// } -// OS.CFRelease(urls); -// } -// OS.CFRelease(escapedStr); -// } -// if (unscapedStr !is 0) OS.CFRelease(unscapedStr); -// OS.CFRelease(str); -// } -// } -// OS.DisposePtr(fsRefPtr); -// } -// return rc is OS.noErr; - return false; + NSAutoreleasePool pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + NSWorkspace workspace = NSWorkspace.sharedWorkspace(); + NSString fullPath = NSString.stringWith(fileName); + if (fileName.indexOf(':') is -1) { + return workspace.openFile(fullPath, NSString.stringWith(name)); + } + NSString unescapedStr = NSString.stringWith("%"); //$NON-NLS-1$ + String lowercaseName = fileName.toLowerCase (); + if (lowercaseName.startsWith (PREFIX_HTTP) || lowercaseName.startsWith (PREFIX_HTTPS)) { + unescapedStr = NSString.stringWith("%#"); //$NON-NLS-1$ + } + int /*long*/ ptr = OS.CFURLCreateStringByAddingPercentEscapes(0, fullPath.id, unescapedStr.id, 0, OS.kCFStringEncodingUTF8); + NSString escapedString = new NSString(ptr); + NSArray urls = NSArray.arrayWithObject(NSURL.URLWithString(escapedString)); + OS.CFRelease(ptr); + return workspace.openURLs(urls, NSString.stringWith(identifier), 0, null, 0); + } finally { + pool.release(); + } } /** @@ -425,51 +306,50 @@ * @return the image data for the program, may be null */ public ImageData getImageData () { -// int[] iconRef = new int[1]; -// OS.GetIconRefFromFileInfo(fsRef, 0, null, 0, 0, 0, iconRef, null); -// int[] family = new int[1]; -// int rc = OS.IconRefToIconFamily(iconRef[0], OS.kSelectorAlLAvailableData, family); -// OS.ReleaseIconRef(iconRef[0]); -// if (rc !is OS.noErr) return null; -//// ImageData result = createImageFromFamily(family[0], OS.kLarge32BitData, OS.kLarge8BitMask, 32, 32); -// ImageData result = createImageFromFamily(family[0], OS.kSmall32BitData, OS.kSmall8BitMask, 16, 16); -// OS.DisposeHandle(family[0]); -// if (result is null) { -// RGB[] rgbs = new RGB[] { -// new RGB(0xff, 0xff, 0xff), -// new RGB(0x5f, 0x5f, 0x5f), -// new RGB(0x80, 0x80, 0x80), -// new RGB(0xC0, 0xC0, 0xC0), -// new RGB(0xDF, 0xDF, 0xBF), -// new RGB(0xFF, 0xDF, 0x9F), -// new RGB(0x00, 0x00, 0x00), -// }; -// result = new ImageData(16, 16, 4, new PaletteData(rgbs) ); -// result.transparentPixel = 6; // use black for transparency -// String[] p= { -// "CCCCCCCCGGG", -// "CFAAAAACBGG", -// "CAAAAAACFBG", -// "CAAAAAACBBB", -// "CAAAAAAAAEB", -// "CAAAAAAAAEB", -// "CAAAAAAAAEB", -// "CAAAAAAAAEB", -// "CAAAAAAAAEB", -// "CAAAAAAAAEB", -// "CAAAAAAAAEB", -// "CAAAAAAAAEB", -// "CDDDDDDDDDB", -// "CBBBBBBBBBB", -// }; -// for (int y= 0; y < p.length; y++) { -// for (int x= 0; x < 11; x++) { -// result.setPixel(x+3, y+1, p[y].charAt(x)-'A'); -// } -// } -// } -// return result; - return null; + NSAutoreleasePool pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + NSWorkspace workspace = NSWorkspace.sharedWorkspace(); + NSString fullPath; + if (this.fullPath !is null) { + fullPath = NSString.stringWith(this.fullPath); + } else { + fullPath = workspace.fullPathForApplication(NSString.stringWith(name)); + } + if (fullPath !is null) { + NSImage nsImage = workspace.iconForFile(fullPath); + if (nsImage !is null) { + NSSize size = new NSSize(); + size.width = size.height = 16; + nsImage.setSize(size); + NSBitmapImageRep imageRep = null; + NSImageRep rep = nsImage.bestRepresentationForDevice(null); + if (rep.isKindOfClass(OS.class_NSBitmapImageRep)) { + imageRep = new NSBitmapImageRep(rep.id); + } + if (imageRep !is null) { + int width = (int)/*64*/imageRep.pixelsWide(); + int height = (int)/*64*/imageRep.pixelsHigh(); + int bpr = (int)/*64*/imageRep.bytesPerRow(); + int bpp = (int)/*64*/imageRep.bitsPerPixel(); + int dataSize = height * bpr; + byte[] srcData = new byte[dataSize]; + OS.memmove(srcData, imageRep.bitmapData(), dataSize); + //TODO check color info + PaletteData palette = new PaletteData(0xFF000000, 0xFF0000, 0xFF00); + ImageData data = new ImageData(width, height, bpp, palette, 4, srcData); + data.bytesPerLine = bpr; + data.alphaData = new byte[width * height]; + for (int i = 3, o = 0; i < srcData.length; i+= 4, o++) { + data.alphaData[o] = srcData[i]; + } + return data; + } + } + } + return null; + } finally { + pool.release(); + } } /** @@ -484,27 +364,6 @@ return name; } -//static Program getProgram(byte[] fsRef) { -// String name = ""; -// int[] namePtr = new int[1]; -// OS.LSCopyDisplayNameForRef(fsRef, namePtr); -// if (namePtr[0] !is 0) { -// int length = OS.CFStringGetLength(namePtr[0]); -// if (length !is 0) { -// char[] buffer= new char[length]; -// CFRange range = new CFRange(); -// range.length = length; -// OS.CFStringGetCharacters(namePtr[0], range, buffer); -// name = new String(buffer); -// } -// OS.CFRelease(namePtr[0]); -// } -// Program program = new Program(); -// program.fsRef = fsRef; -// program.name = name; -// return program; -//} - /** * Compares the argument to the receiver, and returns true * if they represent the <em>same</em> object using a class @@ -517,8 +376,8 @@ */ public bool equals(Object other) { if (this is other) return true; - if ( null !is cast(Program)other ) { - final Program program = cast(Program) other; + if (other instanceof Program) { + final Program program = (Program) other; return name.equals(program.name); } return false;