Code Snippets

This page is intended to provide information on small chunks of code that are of general use, but are not necessarily fully functional blocks. If you are stuck on a coding problem then search this page for the topic/function/keyword of interest, an index is not provided as the list of contents is expected to grow unwieldy.

Note, if some of the code is not visible in the examples below just copy the code and paste it into a text editor to see it all.

Code and keywords

Frog chorus by Dor.

dor = new Frog();
dor.ribbit();


MonitoredWorkQueue, long tasks by David Ekholm.

jAlbum 17+ has a support class that deals with tasks that take a long time to complete. With long running tasks you shouldn't lock the UI but instead run the task on a background thread, but you should also inform the user that a slow task is underway and allow the user to abort the task. All this (but the slow work itself) can now be handled by the new MonitoredWorkQueue class.

Here's a usage example:

MonitoredWorkQueue workQueue = new MonitoredWorkQueue(window, "Convert link to copy");
for (AlbumObject ao : selected) {
    workQueue.submit(() -> {
        File src = LinkFile.targetOf(ao.getFile());
        workQueue.setMessage(ao.getName());
        File target = new File(currentFolder.getFile(), ao.getFile().getName());
        if (src.isDirectory()) {
            target.mkdir();
        }
        IO.copyFile(src, target);
    });
}
workQueue.awaitCompletion();

FileChooser Filter, DeferredChooser, FileFilter, FileNameExtensionFilter By monkeyboy

How to limit the file types that can be selected in a file chooser

import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import se.datadosen.jalbum.DeferredChooser;
 
DeferredChooser fc = new DeferredChooser(JFileChooser.class);
FileFilter filter = new FileNameExtensionFilter(
    "JPEG file", new String[] {"jpg", "jpeg"}
 );
fc.setFileFilter(filter);
ui.fc.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
           int fcReturn = fc.showOpenDialog(window);
           if (fcReturn == JFileChooser.APPROVE_OPTION) {
                  //Your code
               }                
       }
});

Engine, UI, UI2Bean, get settings by David Ekholm

Settings in the user interface don’t get transferred to the JAlbum engine until album generation starts. To update the engine, so all gui settings are correctly reflected use UI2Bean before accessing the engine, e.g.

window.UI2Bean();
engine.getDirectory();

Or query the UI components directly, e.g.

window.directory.getText()

window.bean2UI(), UI, by David Ekholm to refresh the interface from a script

window.bean2UI() 

It will copy the settings from the engine object to the user interface.


Rows, cols, override, reset by David Ekholm

To reset the number of rows and cols during album generation, for example to have the root index with 6 rows and 2 cols, but sub-directories indexes with 5 cols and 4 rows. Use hints.jap to set the rows and cols to 6 and 2 then in index.htt use

If(level == 0) {
  engine.setRows(4);
  engine.setCols(5);
}

ProcessTemplateFile, templates, vars, custom variables by David Ekholm

To pass skin variables from one template to another for processing, e.g. pass variableA from index.htt to MyTemplate.htt:

Map vars = new HashMap();
if(variableA != void) vars.put("variableA", variableA);
if(variableB != void) vars.put("variableB", variableB);
if(variableC != void) vars.put("variableC", variableC);
engine.processTemplateFile(
     new File(skinDirectory,   "MyTemplate.htt"),
     new File(outputDirectory, "MyTemplate.html"),
     vars);

AlbumBean, jAlbumListener, event, engine, JAlbumAdapter , onload, UI, get, set by David Ekholm

To monitor and change settings in onload.bsh when album creation starts and stops. In the example below the page extentension, normally ‘.html’ is changed to ‘.php’ if a skin setting is selected.

import se.datadosen.jalbum.event.*;
window.addJAlbumListener(new JAlbumAdapter() {
  String pageExtension;
 
  public void albumCreationStarted(JAlbumEvent e) {
    pageExtension = engine.getPageExtension();
    if (ui.skinSettingName.isSelected())
      engine.setPageExtension(".php");
  }
 
  public void albumCreationFinished(JAlbumEvent e) {
    engine.setPageExtension(pageExtension);
    engine.bean2UI();
  }
});

You can also use similar code to detect what jAlbum settings have been selected and then do something e.g.

window.addJAlbumListener (
	new JAlbumAdapter() {
		if(engine.getImageLinking().equals("LinkOriginals")) {
                      //Do something
                }
	}
);

AlbumObject, createInstance, file to object by David Ekholm

If you want to convert a file to an album object then this example shows how to do it, with for example a project's root's folder parent folder

File masterProjectFolder = new File(rootFolder.getFile().getParentFile().getParentFile(), rootFolder.getFile().getParentFile().getName());
// Make the master project's folder an object
AlbumObject masterProjectObject = rootFolder.getFactory().createInstance(masterProjectFolder);

Read, Write, File, FileInputStream, DataInputStream, BufferedReader, BufferedWriter based on code by David Ekholm

If you want to read a text file and either do something with or based on its content, and write a changed content back to the file, then one way is:

//Where f is a text file
FileInputStream fStream = new FileInputStream(f);
// make an empty string ready to hold the text of the file
fContent = "";
// Get the object of DataInputStream
DataInputStream fIn = new DataInputStream(fStream);
BufferedReader fBR = new BufferedReader(new InputStreamReader(fIn));
// read the text file line by line
String strLine;
while ((strLine = fBR.readLine()) != null) {
	//Read the whole file (or do something with each strLine)
	fContent = fContent + strLine + "\n";
}
//Close the input stream
fIn.close();
// If the file is to be changed then write the modified file content back out
BufferedWriter newf = new BufferedWriter(new FileWriter(f));
newf.write(fContent);
newf.close();

JTextField, JNumberField , Integer only by Heinz-Peter Bader

If you want to ensure that a JTextField can only contain an integer value use the form below where "yourVariable" accepts Integer only, otherwise the default value "23" is used:

JTextField yourVariable = new JFormattedTextField(new Integer(23));

Another method is to use jAlbum's se.datadosen.component.JNumberField, it has two methods to set whether to allow negative numbers and/or decimals. These setter methods return the JNumberField itself so they can be chained for ease of use:

JNumberField temperature = new JNumberField(10).setAllowNegative(true).setAllowDecimals(true);

JComboBox, listFiles, ChainedDirectory by David Ekholm

Fill a combobox with a list of files of a certain extension, example shows how to get the available styles from a skin's folder.

Note That the ChainedDirectory class is an abstraction for a chained directory structure - it looks first for files in a certain directory, and if not found there, in the chained directory etc.

JComboBox style = new JSmartComboBox();
...
fillCombo(style, new File(skinDir, "styles"),
                    new StyleFileFilter());
 
...
 
    static void fillCombo(JComboBox combo, File dir, FileFilter filter) {
        if (!dir.isDirectory()) {
            return;
        }
        fillCombo(combo, new ChainedDirectory(dir), filter);
    }
 
    static void fillCombo(JComboBox combo, ChainedDirectory dir, FileFilter filter) {
        File[] files = dir.listFiles(filter);
 
        Arrays.sort(files,
                new Comparator() {
 
                    public int compare(Object o1, Object o2) {
                        return String.CASE_INSENSITIVE_ORDER.compare(((File) o1).getName(), ((File) o2).getName());
                    }
                });
 
        for (File f : files) {
            if (f.getName().toLowerCase().endsWith(".css")) {
                combo.addItem(new Item(f.getName(), IO.baseName(f)));
            } else {
                combo.addItem(f.getName());
            }
        }
    }
 
...
 
class StyleFileFilter implements FileFilter {
 
    public boolean accept(File file) {
        String name = file.getName().toLowerCase();
 
        if (file.isDirectory()) {
            return false;
        }
 
        return name.endsWith(".css");
    }
}

Do you know about @Override? by David Ekholm

In Java the @Override annotations won't affect the final code. They only serve as a hint to you as developer that those methods override corresponding methods in super classes. When adding the @Override annotation, the compiler will make sure that you're indeed overriding a method from a super class.


JComboBox , getSelectedIndex() by David Ekholm

Jalbum only automatically passes the string value of a combo box to the album making process (including init.bsh). If you wish to also get the index, you can add a reference to that combo box to the "application" object (a Map type object that has a lifetime as long as Jalbum) and later retrieve it in init.bsh, so in onload.bsh, write:

JComboBox testCombo = new JComboBox(new Object[]
    { "First value", "Second value", "Third value" }
);  
application.put("testCombo", testCombo);

and inside init.bsh, write:

JComboBox testCombo = (JComboBox)application.get("testCombo");

You can now call getSelectedIndex() on that testCombo reference.


Properties, setProperty, getProperty, load, store by TomCee

Example of one of many ways to deal with properties.

import se.datadosen.component.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;
 
Properties props=new Properties();
 
// Controls that are to be imported into JAlbum as variables
 
ControlPanel ui = new ControlPanel() {
  JTextField key=new JTextField(15);
  JTextField value=new JTextField(15);
  JButton savePropsButton=new JButton("save props");
  JButton loadPropsButton=new JButton("load props");
  JButton setPropButton=new JButton("set");
  JButton getPropButton=new JButton("get");
  JTextField retrieveKey=new JTextField(15);
  JTextField retrievedValue=new JTextField(15);
};
 
// Layout controls easily similar to how text is added in a word processor
ui.add(new JLabel("Properties handling example:"));
ui.add("br",new JLabel("key:"));
ui.add(ui.key);
ui.add("tab",new JLabel("value:"));
ui.add("tab",ui.value);
ui.add("br",ui.setPropButton);
ui.add(ui.savePropsButton);
ui.add("br",ui.loadPropsButton);
ui.add("br",new JLabel("type key:"));
ui.add(ui.retrieveKey);
ui.add(ui.getPropButton);
ui.add("br",new JLabel("found value:"));
ui.add(ui.retrievedValue);
 
// Actions
ui.setPropButton.addActionListener(new java.awt.event.ActionListener() {
  public void actionPerformed(java.awt.event.ActionEvent evt) {
            props.setProperty(ui.key.getText(), ui.value.getText());
     }
});
 
ui.savePropsButton.addActionListener(new java.awt.event.ActionListener() {
  public void actionPerformed(java.awt.event.ActionEvent evt) {
    File f = new File("Testprops.properties");
            props.store(new FileOutputStream(f.getName()), "test file for handling properties");
  }
});
 
ui.loadPropsButton.addActionListener(new java.awt.event.ActionListener() {
  public void actionPerformed(java.awt.event.ActionEvent evt) {
        File f = new File("Testprops.properties");
        if (f.exists()) {
              props.load(new FileInputStream(f.getAbsolutePath()));
        }else{
          JOptionPane.showMessageDialog(window, "file not found");
        }
     }
});
 
ui.getPropButton.addActionListener(new java.awt.event.ActionListener() {
  public void actionPerformed(java.awt.event.ActionEvent evt) {
      ui.retrievedValue.setText(props.getProperty(ui.retrieveKey.getText()));
  }
});
 
// Finally install components into JAlbum
window.setSkinUI(ui);

Properties ,.loadFromXML, XML, Read by TomCee

To read an XML file as a properties map.

//init.bsh
import java.util.Properties;
 
 Properties prop = new Properties();
        FileInputStream in = null;
        File f=new File(skinDirectory, "xbfuser.xml");
        in = new FileInputStream(f);
        prop.loadFromXML(in);
        in.close();

engine, addFilter ,.JAFilter by David Ekholm In init.bsh add a jAlbum filter using the constand field values.

engine.addFilter(filter, JAFilter.ALL_PRESCALE_STAGE);

Cameras, putValue, FOCAL_LENGTH_MULTIPLIER by David Ekholm

Internally, the system cameras.properties file is represented by a singleton class called Cameras. You can use a 'putValue' method to it, so skin developers can update and insert new properties to it. Example:

import se.datadosen.jalbum.*;
Cameras cameras = Cameras.getInstance();
cameras.putValue("EASTMAN KODAK COMPANY", "KODAK DC240 ZOOM DIGITAL CAMERA", Cameras.FOCAL_LENGTH_MULTIPLIER, "6.5");
cameras.putValue("Canon", "Canon EOS 450D", Cameras.FOCAL_LENGTH_MULTIPLIER, "1.6216216160602388");



getUserVariables by David Ekholm

Map map = context.getJAlbumContext().getEngine().getUserVariables();

Get the language selected in jAlbum's preference settings by David Ekholm.

import se.datadosen.jalbum.Config;
        String language = Config.getConfig().getLanguage();
        if (language.equals("default")) {
            language = System.getProperty("user.language");
        }

Shorthand for if-then-else script by David Ekholm et al

<%= BooleanVariable ? True condition : False condition %>
 
<%= translucentBackground ? "background-image: url('back.png')" : "background-color: beige" %>;

ProcessTemplateFile, source, destination by David Ekholm

To have Jalbum process a template file and write the result to another file, use this call

engine.processTemplateFile(source, dest);

where source and dest are two File type variables.


VersionNumber, Compare jAlbum API

To compare jAlbum versions, for example a skin might need the latest version but the user might have an older version.

se.datadosen.util.VersionNumber;
int someVariable = VersionNumber.compareTo‚Äč(otherVersionNumber);
//result is 1 if newer, 0 if older

JComboBox, StyleFileFilter jGromit

To fill a combo box with the styles available within the current skin.

JComboBox<String> showStyles = new JComboBox(new String[]{""});
{
	JAlbumUtilities.fillCombo(showStyles, new File(skinDirectory, "styles"), new StyleFileFilter());
}

Accessibility, Class, Field, setAccessibility by David Ekholm

In BeanShell there is however a trick that gives you access to any class, field or method no matter the privacy setting, and that is the setAccessibility(true);


AlbumImage, JAFilter, crop by Gromit

This is to make a new square crop image, for a custom folder image for example, - to do something like a 3:2, you'd need to do a little math to get the setBounds() values. You need to crop the image to the desired aspect ratio before you scale it, or you get very unpleasant results, and to do that, you need to know what its actual dimensions are.

rif = currentObject.getRepresentingImageFile();
if(rif != null) {
	AlbumImage ai = new AlbumImage(rif, engine);
	minDim = Math.min(ai.getBufferedImage().getWidth(), ai.getBufferedImage().getHeight());
	JAFilter sq = new CropFilter();
	sq.setBounds(new Dimension(minDim, minDim));
	ai = ai.applyFilter(sq);
	ai = ai.scaleToFit(new Dimension(400,400));
	ai.saveImage(new File(outputDirectory, "folderthumb.jpg"));
}

themeImage by Gromit

Let's say you've got a couple of JSpinner()'s in your UI for theme image height and width. Now, you want to monitor those, and on any change, alter the theme image dimensions in the engine. Some code that will help:

new StateMonitor() {
	public void onChange() {
		folderImageSize.setText(themeImageWidth.getValue().toString() + "x" + themeImageHeight.getValue().toString());
		engine.setThemeImageDim(new Dimension((int)themeImageWidth.getValue(), (int)themeImageHeight.getValue()));
	}
}.add(themeImageHeight).add(themeImageWidth).done();