сряда, 29 август 2007 г.

Change the System/Boot Drive Letter

1.Make a full system backup of the computer and system state.
2.Log on as an Administrator.
3.Start Regedt32.exe.
4.Go to the following registry key:
HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices
5.Click MountedDevices.
6.On the Security menu, click Permissions.
7.Verify that Administrators have full control. Change this back when you are finished with these steps.
8.Quit Regedt32.exe, and then start Regedit.exe.
9.Locate the following registry key:
HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices
10.Find the drive letter you want to change to (new). Look for "\DosDevices\C:".
11.Right-click \DosDevices\C:, and then click Rename.

Note You must use Regedit instead of Regedt32 to rename this registry key.
12.Rename it to an unused drive letter "\DosDevices\Z:".

This frees up drive letter C.
13.Find the drive letter you want changed. Look for "\DosDevices\D:".
14.Right-click \DosDevices\D:, and then click Rename.
15.Rename it to the appropriate (new) drive letter "\DosDevices\C:".
16.Click the value for \DosDevices\Z:, click Rename, and then name it back to "\DosDevices\D:".
17.Quit Regedit, and then start Regedt32.
18.Change the permissions back to the previous setting for Administrators (this should probably be Read Only).
19.Restart the computer.

петък, 17 август 2007 г.

Rules of Thumb for Ajax Security

1. If you use user authentication, make sure you check for it on the request page!
2. Check for SQL injections.
3. Check for JavaScript injections.
4. Keep the business logic on the server!
5. Don't assume every request is real!
6. Check the data with validation!
7. Look at the request's header information and make sure it is correct.

сряда, 8 август 2007 г.

JavaScript: Create and Delete Options from a Select Box

This is an option box:
<form name="testform">
<select name="testselect">
<option value="first">first option</option>
<option value="second">second option</option>
<option value="third">third option</option>
<option>your browser can't handle this script</option>
</select>
</form>
To access options in a select box, you use the following code:

document.forms['testform'].testselect.options[i]

where i is the number of the option you want to access. Remember that the first option is options[0], the second one is options[1] etc.

Now if you want to delete the option, do

document.forms['testform'].testselect.options[i] = null;

By making it null, the option is completely removed from the list. Note that this also affects the numbering of the options. Suppose you remove option[1] from the example above, the old option[2] ('Third option') becomes option[1] etc.

To create a new option, do:

document.forms['testform'].testselect.options[i] = new Option('new text','new value');

where new text is the text the user sees and new value is the VALUE of the new option, the bit that's sent to the server when the form is submitted. Of course the new option overwrites the old one.

To completely clear a select box, do

document.forms['testform'].testselect.options.length = 0;

четвъртък, 2 август 2007 г.

How to make Apache run ASP.NET / ASP.NET 2.0

1. Install Apache 2.x.xx
2. Install Microsoft.NET Framework and .NET Software Development Kit from here
3. Install the Apache Module: Mod AspDotNet from here
4. Make the following changes to the httpd.conf file of Apache (add at the end of the file):
# ASP.NET start 
LoadModule aspdotnet_module "modules/mod_aspdotnet.so"
AddHandler asp.net asax ascx ashx asmx aspx axd config cs csproj licx rem resources resx soap vb vbproj vsdisco webinfo

<IfModule mod_aspdotnet.cpp>
# Mount the ASP.NET /asp application
AspNetMount /SampleASP "c:/SampleASP"
# /SampleASP is the alias name for asp.net to execute
# "c:/SampleASP" is the actual execution of files/folders in that location

# Map all requests for /asp to the application files
Alias /SampleASP "c:/SampleASP"
# maps /SampleASP request to "c:/SampleASP"
# now to get to the /SampleASP type "http://localhost/SampleASP"
# It'll redirect to "c:/SampleASP"

# Allow asp.net scripts to be executed in the /SampleASP example
<Directory "c:/SampleASP">
Options FollowSymlinks ExecCGI
Order allow,deny
Allow from all
DirectoryIndex index.htm index.aspx
# default the index page to .htm and .aspx
</Directory>

# For all virtual ASP.NET webs, we need the aspnet_client files
# to serve the client-side helper scripts.
AliasMatch /aspnet_client/system_web/(\d+)_(\d+)_(\d+)_(\d+)/(.*) "C:/Windows/Microsoft.NET/Framework/v$1.$2.$3/ASP.NETClientFiles/$4"

<Directory "C:/Windows/Microsoft.NET/Framework/v*/ASP.NETClientFiles">
Options FollowSymlinks
Order allow,deny
Allow from all
</Directory>
</IfModule>

5. Create a directory c:\SampleASP and insert the index.aspx in it.
6. Restart apache server.
7. Open Explorer and navigate to http://localhost/SampleASP/index.aspx.

If everything worked fine you should get a nice ASP.NET page working.

сряда, 1 август 2007 г.

JAR files revealed


What is a JAR file?

The JAR file format is based on the popular ZIP file format, and is used for aggregating many files into one. Unlike ZIP files, JAR files are used not only for archiving and distribution, but also for deployment and encapsulation of libraries, components, and plug-ins, and are consumed directly by tools such as compilers and JVMs. Special files contained in the JAR, such as manifests and deployment descriptors, instruct tools how a particular JAR is to be treated.

A JAR file might be used:
  • For distributing and using class libraries

  • As building blocks for applications and extensions

  • As deployment units for components, applets, or plug-ins

  • For packaging auxiliary resources associated with components
The JAR file format provides many benefits and features, many of which are not provided with a traditional archive format such as ZIP or TAR. These include:
  • Security. You can digitally sign the contents of a JAR file. Tools that recognize your signature can then optionally grant your software security privileges it wouldn't otherwise have, and detect if the code has been tampered with.

  • Decreased download time. If an applet is bundled in a JAR file, the applet's class files and associated resources can be downloaded by a browser in a single HTTP transaction, instead of opening a new connection for each file.

  • Compression. The JAR format allows you to compress your files for efficient storage.

  • Transparent platform extension. The Java Extensions Framework provides a means by which you can add functionality to the Java core platform, which uses the JAR file for packaging of extensions. (Java 3D and JavaMail are examples of extensions developed by Sun.)

  • Package sealing. Packages stored in JAR files can be optionally sealed to enforce version consistency and security. Sealing a package means that all classes defined in that package must be found in the same JAR file.

  • Package versioning. A JAR file can hold data about the files it contains, such as vendor and version information.

  • Portability. The mechanism for handling JAR files is a standard part of the Java platform's core API.

Compressed and uncompressed JARs

The jar tool (see The jar tool for details) compresses files by default. Uncompressed JAR files can generally be loaded more quickly than compressed JAR files, because the need to decompress the files during loading is eliminated, but download time over a network may be longer for uncompressed files.

The META-INF directory

Most JAR files contain a META-INF directory, which is used to store package and extension configuration data, such as security and versioning information. The following files or directories in the META-INF directory are recognized and interpreted by the Java 2 platform for configuring applications, extensions, and class loaders:

  • MANIFEST.MF. The manifest file defines the extension- and package-related data.

  • INDEX.LIST. This file is generated by the new -i option of the jar tool and contains location information for packages defined in an application or extension. It is part of the JarIndex implementation and used by class loaders to speed up the class loading process.

  • xxx.SF. This is the signature file for the JAR file. The placeholder xxx identifies the signer.

  • xxx.DSA. The signature block file associated with the signature file stores the public signature used to sign the JAR file.

The jar tool

To perform basic tasks with JAR files, you use the Java Archive Tool (jar tool) provided as part of the Java Development Kit. You invoke the jar tool with the jar command. Table 1 shows some common applications:

Table 1. Common usages of the jar tool

FunctionCommand
Creating a JAR file from individual filesjar cf jar-file input-file...
Creating a JAR file from a directoryjar cf jar-file dir-name
Creating an uncompressed JAR filejar cf0 jar-file dir-name
Updating a JAR filejar uf jar-file input-file...
Viewing the contents of a JAR filejar tf jar-file
Extracting the contents of a JAR filejar xf jar-file
Extracting specific files from a JAR filejar xf jar-file archived-file...
Running an application packaged as an executable JAR filejava -jar app.jar



Executable JARs

An executable jar file is a self-contained Java application stored in a specially configured JAR file, which can be executed directly by the JVM without having to first extract the files or set up a class path. To run an application stored in a non-executable JAR, you have to add it to your class path and invoke the application's main class by name. But by using executable JAR files, we can run an application without extracting it or needing to know the main entry point. Executable JARs facilitate easy distribution and execution of Java applications.

Creating executable JARs

Creating an executable JAR is easy. You begin by placing all your application code in a single directory. Let's say the main class in your application is com.mycompany.myapp.Sample. You want to create a JAR file that contains the application code and identifies the main class. To do this, create a file called manifest somewhere (not in your application directory), and add the following line to it:

Main-Class: com.mycompany.myapp.Sample
Then, create the JAR file like this:

jar cmf manifest ExecutableJar.jar application-dir
That's all there is to it -- now the JAR file ExecutableJar.jar can be executed using java -jar.

An executable JAR must reference all the other dependent JARs it requires through the Class-Path header of the manifest file. The environment variable CLASSPATH and any class path specified on the command line is ignored by the JVM if the -jar option is used.

Launching executable JARs

Now that we've packaged our application into an executable JAR called ExecutableJar.jar, we can launch the application directly from the file using the following command:

java -jar ExecutableJar.jar

Package sealing

Sealing a package within a JAR file means that all classes defined in that package must be found in the same JAR file. This allows the package author to enforce version consistency among packaged classes. Sealing also provides a security measure to detect code tampering.

To seal a package, add a Name header for the package, followed by a Sealed header with value "true" to the JAR manifest file. Just as with executable JARs, you can seal a JAR by specifying a manifest file with the appropriate header elements when the JAR is created, as shown here:

Name: com/samplePackage/
Sealed: true
The Name header identifies the package's relative pathname. It ends with a "/" to distinguish it from a filename. Any headers following a Name header, without any intervening blank lines, apply to the file or package specified in the Name header. In the example above, because the Sealed header occurs after the Name header without intervening blank lines, the Sealed header will be interpreted as applying only to the package com/samplePackage.

If you try to load a class in a sealed package from another source other than the JAR file in which the sealed package lives, the JVM will throw a SecurityException.

Packaging for extensions

Extensions add functionality to the Java platform, and an extensions mechanism is built into the JAR file format. The Extensions mechanism allows JAR files to specify other required JAR files via the Class-Path headers in the manifest file.

Let's say that extension1.jar and extension2.jar are two JAR files in the same directory, with the manifest of extension1.jar containing the following header:

Class-Path: extension2.jar
This header indicates that the classes in extension2.jar serve as extension classes for purposes of the classes in extension1.jar. The classes in extension1.jar can invoke classes in extension2.jar without extension2.jar having to be part of the class path.

The JVM effectively automatically adds JARs referenced in a Class-Path header to the class path when loading a JAR that uses the extension mechanism. However, the extension JAR path is interpreted as a relative path, so in general the extension JAR must be stored in the same directory as the JAR referencing it.

For example, assume the class ExtensionClient, which references class ExtensionDemo, is bundled in a JAR file called ExtensionClient.jar, and that the class
ExtensionDemo is bundled in ExtensionDemo.jar. In order for ExtensionDemo.jar to be treated as an extension, ExtensionDemo.jar must be listed in the Class-Path header in ExtensionClient.jar's manifest, as follows:

Manifest-Version: 1.0
Class-Path: ExtensionDemo.jar
The value of the Class-Path header in this manifest is ExtensionDemo.jar with no path specified, indicating that ExtensionDemo.jar is located in the same directory as the ExtensionClient JAR file.

Security in JAR files

A JAR file can be signed by using the jarsigner tool or directly through the java.security API. A signed JAR file is exactly the same as the original JAR file, except that its manifest is updated, and two additional files are added to the META-INF directory, a signature file and a signature block file.

A JAR file is signed using a certificate stored in the Keystore database. Certificates stored in the keystore are protected with a password, which must be provided to the jarsigner tool to sign a JAR file.

Figure 1. Keystore database

Keystore Database

Each signer of a JAR is represented by a signature file with the extension .SF within the META-INF directory of the JAR file. The format of the file is similar to the manifest file -- a set of RFC-822 headers. As shown below, it consists of a main section, which includes information supplied by the signer but not specific to any particular JAR file entry, followed by a list of individual entries which also must be present in the manifest file. To validate a file from a signed JAR, a digest value in the signature file is compared against a digest calculated against the corresponding entry in the JAR file.

Listing 1. Manifest and signature files in signed JARs

Contents of signature file META-INF/MANIFEST.MF

Manifest-Version: 1.0
Created-By: 1.3.0 (Sun Microsystems Inc.)

Name: Sample.java
SHA1-Digest: 3+DdYW8INICtyG8ZarHlFxX0W6g=

Name: Sample.class
SHA1-Digest: YJ5yQHBZBJ3SsTNcHJFqUkfWEmI=

Contents of signature file META-INF/JAMES.SF

Signature-Version: 1.0
SHA1-Digest-Manifest: HBstZOJBuuTJ6QMIdB90T8sjaOM=
Created-By: 1.3.0 (Sun Microsystems Inc.)

Name: Sample.java
SHA1-Digest: qipMDrkurQcKwnyIlI3Jtrnia8Q=

Name: Sample.class
SHA1-Digest: pT2DYby8QXPcCzv2NwpLxd8p4G4=
Digital signatures

A digital signature is a signed version of the .SF signature file. Digital signature files are binary files and have the same filename as the .SF file but a different extension. The extension varies depending on the type of digital signature -- RSA, DSA, or PGP -- and on the type of certificate used to sign the JAR.

Keystore

To sign a JAR file, you must first have a private key. Private keys and their associated public-key certificates are stored in password-protected databases called keystores. The JDK contains tools for creating and modifying keystores. Each key in the keystore can be identified by an alias, which is typically the name of the signer who owns the key.

All keystore entries (key and trusted certificate entries) are accessed with unique aliases. An alias is specified when you add an entity to the keystore using the keytool -genkey command to generate a key pair (public and private key). Subsequent keytool commands must use this same alias to refer to the entity.

For example, to generate a new public/private key pair with the alias "james" and wrap the public key into a self-signed certificate, you would use with the following command:

keytool -genkey -alias james -keypass jamespass
-validity 80 -keystore jamesKeyStore
-storepass jamesKeyStorePass
This command sequence specifies an initial password of "jamespass" required by subsequent commands to access the private key associated with the alias "james" in the keystore "jamesKeyStore." If the keystore "jamesKeyStore" does not exist, keytool will automatically create it.

The jarsigner tool

The jarsigner tool uses keystore to generate or verify digital signatures for JAR files.

Assuming you've created the keystore "jamesKeyStore" as in the example above, and it contains a key with alias "james," you can sign a JAR file with the following command:

jarsigner -keystore jamesKeyStore -storepass jamesKeyStorePass
-keypass jamespass -signedjar SSample.jar Sample.jar james
This command fetches the key whose alias is "james" and whose password is "jamespass" from the keystore named "jamesKeyStore" with the password "jamesKeyStorePass," and signs the Sample.jar file, creating a signed JAR, SSample.jar.

The jarsigner tool can also verify a signed JAR file; this operation is considerably simpler than signing the JAR file. Just execute the following command:

jarsigner -verify SSample.jar
If the signed JAR file has not been tampered with, the jarsigner tool will tell you the JAR has been verified; otherwise, it will throw a SecurityException indicating which files could not be verified.

JARs can also be signed programmatically using the java.util.jar and java.security APIs. Alternatively, you can use tools such as Netscape Object Signing Tool.

You can also sign JARs programmatically using the java.util.jar and java.security APIs. (See Resources for details). Alternatively, you can use tools such as the Netscape Object Signing Tool.


JAR indexing

If an application or applet is bundled into multiple JAR files, the class loader uses a simple linear search algorithm to search each element of the class path, which may entail the class loader downloading and opening many JAR files until the class or resource is found. If the class loader tries to find a nonexistent resource, all the JAR files within the application or applet will have to be downloaded. For large network applications and applets this could result in slow start up, sluggish response, and wasted network bandwidth.

Since JDK 1.3, the JAR file format has supported indexing to optimize the process of searching for classes in network applications, especially applets. The JarIndex mechanism collects the contents of all the JAR files defined in an applet or application and stores the information in an index file in the first JAR file. After the first JAR file is downloaded, the applet class loader will use the collected content information for efficient downloading of JAR files. This directory information is stored in a simple text file named INDEX.LIST in the META-INF directory of the root JAR file.

Creating a JarIndex

You can create a JarIndex by specifying the -i option to the jar command. Suppose we have a directory structure as depicted in the following diagram:

Figure 2. JarIndex


JarIndex Demo

You would use the following command to create an index file for JarIndex_Main.jar, JarIndex_test.jar, and JarIndex_test1.jar:

jar -i JarIndex_Main.jar JarIndex_test.jar SampleDir/JarIndex_test1.jar
The INDEX.LIST file has a simple format, containing the names of the packages or classes contained in each JAR file indexed, as shown in Listing 2:

Listing 2. Example JarIndex INDEX.LIST file

JarIndex-Version: 1.0

JarIndex_Main.jar
sp

JarIndex_test.jar
Sample

SampleDir/JarIndex_test1.jar
org
org/apache
org/apache/xerces
org/apache/xerces/framework
org/apache/xerces/framework/xml4j


Summary

The JAR format is much more than an archive format; it has many features for improving the efficiency, security, and organization of Java applications. Because these features are built into the core platform, including the compiler and classloader, developers can leverage the power of the JAR file format to simplify and improve their development and deployment processes.

петък, 27 юли 2007 г.

Creating a custom UI delegate for JTabbedPane

This article was found on someone's blog, and I copied it here to preserve it in case that blog goes down. I find it very informative and thorough. At the end of the article, there is a link to the original post.

In my opinion one of the most underappreciated (and perhaps underused) features of Swing is the ability to create custom UI delegates for existing controls. It seems to me that most of the time new delegates are only created as part of developing a new complete look and feel, however I think they could be better leveraged to help add polish to existing applications.

For example, if you look at an application like Adobe Photoshop, in order to save space in their palettes, they use a small tab control. The same goes for most of the Microsoft Office products. They each contain customized tab controls that better integrate into the confinements of their respective user interfaces. Functionally, these behave like a standard tab controls, however the look and feel of these are different.

Over the years, I’ve seen many custom Swing controls implemented where the developers have re-implemented all that logic that already exists in an existing control with the only purpose of creating a version of that control that looks different. In fact, I know that I am guilty of doing that as well. Doesn’t it seem stupid to have to reimplement the logic for a button, a tab control, a checkbox or whatever control you are trying to create if your only goal is to change the way it looks?

Luckily for us Swing developers, there is a way just to address this exact problem. :-)

I thought a good (and simple) example of how to implement a custom UI delegate would be to create an implementation for JTabbedPane that makes it look like the tabs used in the palletes of Adobe Photoshop:

An example of how the tabs look in an Adobe Photoshop palette

These tabs are simple enough, that we can implement this with little effort, and it will be (hopefully) a good example of how to create your own UI delegate.

Step 1: Create a new delegate class

If you’ve ever dug into the implementation of the different look and feels of Swing, you see that all the look and feels extend a basic look and feel implementation (in the javax.swing.plaf.basic package). These “basic” implementations (generally) break down the drawing of the respective controls into smaller units to make it easier to create a new delegates.

Since we want to create a new delegate for JTabbedPane, our new class needs to extend the BasicTabbedPaneUI class:

import javax.swing.plaf.basic.BasicTabbedPaneUI;

public class PSTabbedPaneUI extends BasicTabbedPaneUI
{

}
Believe it or not, this is actually enough to start using this “custom” delegate in a real application. In the next step, we will create a test application that we can use to see the transformation as we implement our look and feel.

Step 2: Create a small application to test our tabs



In order to test our new delegate, we need to create a small application that will use it. In order to get a good idea of how the delegate behaves, we will create a panel with three tabs in it. Tab 1 will contain a standard JPanel; Tab 2 will contain a JPanel with a black, 2 pixel border; and Tab 3 will contain a JButton. The reason we will do this, is that we can see the changes to the border of the content area of the tab, as well as the insets of the content area.


Here is the code that we will use for our sample application:

public class TestPSTabbedPaneUI
{
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception exc)
{
// Do nothing...
}

JFrame vFrame = new JFrame();
vFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
vFrame.setSize(200, 200);
JTabbedPane vTab = new JTabbedPane();
vTab.setUI(new PSTabbedPaneUI());

vTab.add(\"One\", new JPanel());

JPanel vPanel2 = new JPanel();
vPanel2.setBorder(BorderFactory.createLineBorder(Color.BLACK,2));
vTab.add(\"Two\", vPanel2);

vTab.add(\"Three\", new JButton(\"three\"));

vFrame.getContentPane().add(vTab);
vFrame.setTitle(\"Tabs Example\");
vFrame.show();
}
}
If we would run this right now, we would see the following:

As you can see, the application runs and is usable, but the tabs just look like standard (older) Windows style tabs. We can now begin with the fun stuff, actually changing the way the tabs are presented.

Step 3: Customize the way the tabs are drawn

In order to change the way the tabs are drawn, we need to override the paintTabBorder method. If you look closely at the the tabs in Photoshop, you will see that in addition to having a border, there is a “beveled” look to the selected tab. It has a white line inside the left and top edge of the, and with a darker gray line inside of the right hand (angled) side. We will implement this beveled look in the paintTabBorder method as well:

 protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected)
{
g.setColor(Color.BLACK);
g.drawLine(x, y, x, y + h);
g.drawLine(x, y, x + w - (h / 2), y);
g.drawLine(x + w - (h / 2), y, x + w + (h / 2), y + h);

if (isSelected)
{
g.setColor(Color.WHITE);
g.drawLine(x + 1, y + 1, x + 1, y + h);
g.drawLine(x + 1, y + 1, x + w - (h / 2), y + 1);

g.setColor(shadow);
g.drawLine(x + w - (h / 2), y + 1, x + w + (h / 2)-1, y + h);
}
}
If we would run this right now, we would see the following:

It’s still pretty ugly, but as you can see, by changing overriding one method, we already have made a drastic change to the way it looks.

Step 4: Customize the way the tabs are painted

If you look at the selected tab in the screenshots from step 3, you can see that you can see the edge of the border of the adjacent tabs. The next thing we will want to do is clean that up. In order to do that, we can extend the paintTabBackground method. In this method, we will simply create a polygon which is the shape of the tab and fill it with the background color of the tab pane:

 protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected)
{
Polygon shape = new Polygon();

shape.addPoint(x, y + h);
shape.addPoint(x, y);
shape.addPoint(x + w - (h / 2), y);

if (isSelected || (tabIndex == (rects.length - 1)))
{
shape.addPoint(x + w + (h / 2), y + h);
}
else
{
shape.addPoint(x + w, y + (h / 2));
shape.addPoint(x + w, y + h);
}

g.setColor(tabPane.getBackground());
g.fillPolygon(shape);
}
If we would run this right now, we would see the following:

With that simple change, the tabs themselves look a lot cleaner and a lot more polished, however there is still alot we need to do finish things off.

Step 5: Supress the painting of the focus indicator

If you look at the Photoshop screenshot, there is no focus indicator for the tabs. Additionally, if you look at the screenshots from Step 4, you will notice that that the focus indicators are rectangular, while the buttons are not. In order to simulate the way the Photoshop tabs are implemented, we are going to supress the painting of the focus indicator. In order to do this, we just need to override the paintFocusIndicator method and have it do nothing:

 protected void paintFocusIndicator(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect, boolean isSelected)
{
// Do nothing
}

If we run our sample application now, we would see the following:

Without the focus indicator painted, it looks alot more like the original control we are copying.

Step 6: Change the insets of the tab bar

If look at the screenshot of the Photoshop tabs, you will notice that there is a 4 pixel gap between the left edge of the first tab (”Layers”) and the left hand side of the container. In our current version, the left hand side of the tab is directly agains the left edge of the container.

Additionally, if you look at our current version, you will see that the text for the tabs are inset a few pixels farther from the top edge of the tab than in the original Photoshop tab.

In order to fix this, we need to override the installDefaults method and change the default values for the insets. To fix problem number 1, we will need to modify the tabAreaInsets field, and to fix problem number 2, we will need to modify the selectedTabPadInsets field and the tabInsets field:

 protected void installDefaults()
{
super.installDefaults();
tabAreaInsets.left = 4;
selectedTabPadInsets = new Insets(0, 0, 0, 0);
tabInsets = selectedTabPadInsets;
}
If we run our sample application now, we would see the following:

While we fixed the problem with the insets, the changes make our tabs look alot worse than before. In order to make them look better, we need a way to specify their size.

Step 7: Specify the size of the tabs

In order to specify the size of the tabs we need to override the calculateTabHeight method and the calculateTabWidth method. We can also use the calculateTabHeight method to enforce the fact that a tab will always be a height that is divisible by two. This will make sure that the angled line on the right hand side of the tabs always looks good (unlike the screenshots from the previous step).

 protected int calculateTabHeight(int tabPlacement, int tabIndex, int fontHeight)
{
int vHeight = fontHeight;
if (vHeight % 2 > 0)
{
vHeight += 1;
}
return vHeight;
}

protected int calculateTabWidth(int tabPlacement, int tabIndex, FontMetrics metrics)
{
return super.calculateTabWidth(tabPlacement, tabIndex, metrics) + metrics.getHeight();
}
If we run our sample application now, we would see the following:

These changes now give our tabs the right proportions as compared to the real tabs in Photoshop. We can now turn our attention to the text of the tabs.

Step 8: Change the way the text is drawn

In Photoshop, the selected tab always has it’s text drawn in bold. Additionally, if you look at the text of all of the tabs in Photoshop, you will see they are all drawn at the same y location. In our tabs, the text for the selected tab is always drawn 2 pixels higher than the rest. In order to fix these problems, we will need to override a few methods.

First of all, we need to create the bold font to use to draw the selected text. We can create that font in the installDefaults method where we specified the custom insets:

 protected void installDefaults()
{
super.installDefaults();
tabAreaInsets.left = 4;
selectedTabPadInsets = new Insets(0, 0, 0, 0);
tabInsets = selectedTabPadInsets;

boldFont = tabPane.getFont().deriveFont(Font.BOLD);
boldFontMetrics = tabPane.getFontMetrics(boldFont);
}

Note: In a “real” delegate, you would additionally want to listen for the font property of the tabPane to change so that you could update the cached bold font. For our simple example, we’ll overlook that small detail to simplify things.

Next, in order to prevent the text of the selected tab to be drawn at a different y location than the unselected tabs, we need to override the getTabLabelShiftY method:

 protected int getTabLabelShiftY(int tabPlacement, int tabIndex, boolean isSelected)
{
return 0;
}

Finally, in order to paint the text in a bold font for the selected text, we need to override the paintText method:

 protected void paintText(Graphics g, int tabPlacement, Font font, FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected)
{
if (isSelected)
{
int vDifference = (int)(boldFontMetrics.getStringBounds(title,g).getWidth()) - textRect.width;
textRect.x -= (vDifference / 2);
super.paintText(g, tabPlacement, boldFont, boldFontMetrics, tabIndex, title, textRect, isSelected);
}
else
{
super.paintText(g, tabPlacement, font, metrics, tabIndex, title, textRect, isSelected);
}
}
If we run our sample application now, we would see the following:

Step 9: Paint the background behind the tabs

If you look at the background behind (and to the right) of the tabs in Photoshop, it is painted a little bit darker than the color of the tabs. In order to implement this, we need to override the paintTabArea method.

Before we do that however, we need to decide what color to paint the background. In order to make this delegate work fairly well with any look and feel, we will simply create a darker version of the background color by calling the darker()<> method on the background color. We can add the creation of this color to the installDefaults method like we’ve done before:

 protected void installDefaults()
{
super.installDefaults();
tabAreaInsets.left = 4;
selectedTabPadInsets = new Insets(0, 0, 0, 0);
tabInsets = selectedTabPadInsets;

Color background = tabPane.getBackground();
fillColor = background.darker();

boldFont = tabPane.getFont().deriveFont(Font.BOLD);
boldFontMetrics = tabPane.getFontMetrics(boldFont);
}
Now that we have that out of the way, we can implement the paintTabArea method:
 protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex)
{
int tw = tabPane.getBounds().width;

g.setColor(fillColor);
g.fillRect(0, 0, tw, rects[0].height + 3);

super.paintTabArea(g, tabPlacement, selectedIndex);
}
If we run our sample application now, we would see the following:

The color is a little darker than in the original, however by implementing it this way, the delegate should be reusable between any look and feel (and any background color). You’ll also notice that we have the same issue with the font. The font does match up exactly, but by using the default font for the look and feel, we make the delegate more portable.

Step 10: Change the way the top border of the content area is drawn

If you at the screenshot from the previous step where tab “One” is selected, you will notice that there are a few problems with how the top line of the content area is painted. First of all, the Photoshop tabs have a black line there as opposed to a while line. Secondly, there is a bevel effect in the real version, and finally in our (current) version, the lines don’t even match up to the border of the tabs (on the right hand side of the tab where the angle comes down).

In order to fix this, we will need to override the paintContentBorderTopEdge method:

 protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h)
{
Rectangle selectedRect = selectedIndex < width =" selectedRect.width">
If we run our sample application now, we would see the following:

With those changes, we are now done with the tab area itself. Now, we just need to clean up the borders (actually remove them) of the content area.

Step 11: Removing the borders in the content area

In order to remove the borders of the content area, we just need to override the methods paintContentBorderRightEdge, paintContentBorderLeftEdge and paintContentBorderBottomEdge and have them do nothing:

 protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h)
{
// Do nothing
}

protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h)
{
// Do nothing
}

protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h)
{
// Do nothing
}
If we run our sample application now, we would see the following:

If you look at the screenshot where “One” is selected, you might think we are done with our delegate. However, if you look at the screenshot where tab “Two” is selected, you will notice that the content is still inset a little bit from the edges. In the orignal Photoshop tab, there is no inset, so we still need to remove that before we can be finished.

Step 12: Removing the content area insets

Implementing this turns out to be quite simple as well. All we need to do is override the getContentBorderInsets method:
 protected Insets getContentBorderInsets(int tabPlacement)
{
return new Insets(2, 0, 0, 0);
}

The reason the insets have a pixel height of 2 for the top is that we need to inset for the black line and the white “bevel” line below it.

If we run our sample application now, we would see the following:

If you look at the screenshot where the tab “Two” is selected, you can now see that content area extends to the borders exactly like the Photoshop example.

If you want to play with the example yourself, you can download the source code for the delegate here, and you can download the source code for the test application here.

четвъртък, 19 юли 2007 г.

External JavaScript Character Set Encoding for Firefox and Internet Explorer

The SCRIPT tag has an attribute "charset" which can be set to a specific encoding so the browser knows how to interpret the external JavaScript file. This works fine with Firefox, but not with IE.

I have found that for me to force IE to display non-English characters from an external JavaScript file, where a dynamic element is added to the page on the fly, the best way to handle this is via the "native2ascii" application from JDK.

native2ascii somefile.js

will encode any non-ASCII characters with their Unicode equivalents, so the browser will convert them correctly to the actual text.

JavaScript: Replace Text Found in a Node and its Subnodes of the DOM Tree

The following examples replaces the letter "l" or "L" with "r" or "R" respectively. It gets a DOM element, and traverses it along with its children, and performs the operation.

function engrish(n)
{
if(n.nodeType == document.TEXT_NODE)
{
n.nodeValue = n.nodeValue.replace(/l/g, 'r').replace(/L/g, 'R');
}
else if(n.hasChildNodes())
{
for(var i=0; i < n.childnodes.length; i++)
engrish(n.childNodes[i]);
}
}
}

Add and Remove HTML elements dynamically with Javascript

Here is some simple JavaScript. With some tweaking, you may fit it on your webpage.


function addElement()
{
var ni = document.getElementById('myDiv');
var numi = document.getElementById('theValue');
var num = (document.getElementById('theValue').value -1)+ 2;
numi.value = num;
var newdiv = document.createElement('div');
var divIdName = 'my'+num+'Div';
newdiv.setAttribute('id',divIdName);
newdiv.innerHTML = "Some contents";
ni.appendChild(newdiv);

// For IE, set any attributes directly;
// do not use the setAttribute method().
// E.g. use newdiv.style.zIndex = "1000" instead of
// newdiv.setAttribute('style','z-index: 1000;');
}

function removeElement(divNum)
{
var d = document.getElementById('myDiv');
var olddiv = document.getElementById(divNum);
d.removeChild(olddiv);
}

събота, 14 юли 2007 г.

Dell Inspiron 9400 Manual

http://support.dell.com/support/edocs/systems/ins9400/en/om/index.htm

четвъртък, 28 юни 2007 г.

Windows Vista Home Basic & the Aero Glass Theme

After a long research on how to make Windows Vista Home Basic run the Aero Glass theme (which is available only for the Premium, Businessm, and Ultimate editions of Windows), I found a nifty program that patches the original Windows files. Why do I want to do this? Well, my laptop came with Windows Vista Home Basic, and the upgrade just not worth the money. The program that does this is called VistaGlazz. I haven't tested it yet, but it claims to enable the Aero Glass interface on the Home Basic OS. I will try it out and will post my results later.