Tagged “snippet”

Drupal: Login-Screen instead of 403

Published by cybso on

This is a post from my original site, which was hosted by the former blog service of the University of Osnabrück. I have moved it to the new site for archiving. Pages linked in this article may no longer work today, and the blog comments under the article no longer exist. Opinions expressed in this article reflect the point of view of the time of publication and do not necessarily reflect my opinion today.

If you're running a Drupal-based webpage which is completely restricted to authenticated users, Anonymous would get an "403 Access Denied" on every page he tries. But if you want your visitors to see a friendly login page (instead of just this error message and a small "login block") you might want to put the following code into your sites/default/setting.php:

function custom_url_rewrite($op, $result, $path) {
    global $user;
    if (!$user->uid) {
        return "user/login";
    }
    return $path;
}

You should also check $path if you want to use this on some pages only, e.g. on your frontpage.

UPDATE: This code is erroneous! You should return $result instead of $path, or some other modules like pathauto or path_redirect won't work as expected!

Create screenshots of a web page using Python and QtWebKit

Published by cybso on

This is a post from my original site, which was hosted by the former blog service of the University of Osnabrück. I have moved it to the new site for archiving. Pages linked in this article may no longer work today, and the blog comments under the article no longer exist. Opinions expressed in this article reflect the point of view of the time of publication and do not necessarily reflect my opinion today.

Update 2009-10-03:

For further development and improvements, contact me or have a look at this public github repository created by Adam Nelson.

Update 2010-04-12:

If you need flash support, you should have a look at the current github version of this script at http://github.com/AdamN/python-webkit2png/ mentioned above. We've extend the script a few month ago.


From time to time you may want to create a screenshot of a web page from command line, for example if you wish to create thumbnails for your web-application. So you might search for such a program and find tools like webkit2png, which is for Mac OS X only, or khtml2png, which requires a lot of KDE stuff to be installed on your server.

But since Qt Software, formerly known als Trolltech, integrated Safari's famous rendering engine WebKit (which is based on Konqueror's khtml engine) into its framework, we are now able to make use of it with the help of some Python and PyQt4.

(continue reading)

Symfony: Merge embedded Form (Update)

Published by cybso on

This is a post from my original site, which was hosted by the former blog service of the University of Osnabrück. I have moved it to the new site for archiving. Pages linked in this article may no longer work today, and the blog comments under the article no longer exist. Opinions expressed in this article reflect the point of view of the time of publication and do not necessarily reflect my opinion today.

Symfony provides a nice feature called "embedded Forms" ( sfForm::embedForm) to embed subforms into a parent form. This can be used to edit multiple records at the same time. So let's say you have a basic user table called 'sf_guard_user' and a profile table called 'user_profile', then you might follow this guide to merge these forms together: lib/forms/doctrine/sfUserGuardAdminForm.php:

class sfGuardUserAdminForm extends BasesfGuardUserAdminForm
{
  public function configure()
  {
    parent::configure();

    // Embed UserProfileForm into sfGuardUserAdminForm
    $profileForm = new UserProfileForm($this->object->Profile);
    unset($profileForm['id'], $profileForm['sf_guard_user_id']);
    $this->embedForm("profile", $profileForm);
  }
}

Remember to add "profile" to the list of visible columns in apps/backend/modules/sfGuardUser/config/generator.yml as decribed in the linked guide. The result may look like this:

This does what it is expected to do, but it doesn't look very nice. Especially for 1:1 related tables I'm more interested in a solution that looks like this:

You can reach this using sfForm::mergeForm, but sadly the merged model won't get updated and you'll run into problems if the forms are sharing fieldnames. The solution is the following method embedMergeForm which can be defined in BaseFormDoctrine to be avaible in all other forms:

lib/forms/doctrine/BaseFormDoctrine.php:

abstract class BaseFormDoctrine extends sfFormDoctrine
{
  /**
   * Embeds a form like "mergeForm" does, but will still
   * save the input data.
   */
  public function embedMergeForm($name, sfForm $form)
  {
    // This starts like sfForm::embedForm
    $name = (string) $name;
    if (true === $this->isBound() || true === $form->isBound())
    {
      throw new LogicException('A bound form cannot be merged');
    }
    $this->embeddedForms[$name] = $form;

    $form = clone $form;
    unset($form[self::$CSRFFieldName]);

    // But now, copy each widget instead of the while form into the current
    // form. Each widget ist named "formname|fieldname".
    foreach ($form->getWidgetSchema()->getFields() as $field => $widget)
    {
      $widgetName = "$name|$field";
      if (isset($this->widgetSchema[$widgetName]))
      {
        throw new LogicException("The forms cannot be merged. A field name '$widgetName' already exists.");
      }

      $this->widgetSchema[$widgetName] = $widget;                           // Copy widget
      $this->validatorSchema[$widgetName] = $form->validatorSchema[$field]; // Copy schema
      $this->setDefault($widgetName, $form->getDefault($field));            // Copy default value

      if (!$widget->getLabel())
      {
        // Re-create label if not set (otherwise it would be named 'ucfirst($widgetName)')
        $label = $form->getWidgetSchema()->getFormFormatter()->generateLabelName($field);
        $this->getWidgetSchema()->setLabel($widgetName, $label);
      }
    }

    // And this is like in sfForm::embedForm
    $this->resetFormFields();
  }

  /**
   * Override sfFormDoctrine to prepare the
   * values: FORMNAME|FIELDNAME has to be transformed
   * to FORMNAME[FIELDNAME]
   */
  public function updateObject($values = null)
  {
    if (is_null($values))
    {
      $values = $this->values;
      foreach ($this->embeddedForms AS $name => $form)
      {
        foreach ($form AS $field => $f)
        {
          if (isset($values["$name|$field"]))
          {
            // Re-rename the form field and remove
            // the original field
            $values[$name][$field] = $values["$name|$field"];
            unset($values["$name|$field"]);
          }
        }
      }
    }

    // Give the request to the original method
    parent::updateObject($values);
  }
}

This method ensures that each fieldname is unique (named 'FORMNAME|FIELDNAME') and the subform is validated and saved. It is used like embedForm:

lib/forms/doctrine/sfUserGuardAdminForm.php:

class sfGuardUserAdminForm extends BasesfGuardUserAdminForm
{
  public function configure()
  {
    parent::configure();

    // Embed UserProfileForm into sfGuardUserAdminForm
    // without looking like an embedded form
    $profileForm = new UserProfileForm($this->object->Profile);
    unset($profileForm['id'], $profileForm['sf_guard_user_id']);
    $this->embedMergeForm("profile", $profileForm);
  }
}

Feel free to use this method in your own project. Maybe this method get's merged into Symfony some day ;-)

Update

frostpearl reported a problem using embedFormMerge() in conjunction with the autocompleter widget from sfFormExtraPlugin. If you expire these problems try to replace all occurences of $name|$field with $name-$field.

Flex 3: Upload multiple files via POST with AS3

Published by cybso on

This is a post from my original site, which was hosted by the former blog service of the University of Osnabrück. I have moved it to the new site for archiving. Pages linked in this article may no longer work today, and the blog comments under the article no longer exist. Opinions expressed in this article reflect the point of view of the time of publication and do not necessarily reflect my opinion today.

In my current Abobe Flex project, I needed to upload multple generated files and form fields to a server. UploadPostHelper by Jonathan Marston is a great for uploading one file at time, but sadly I couldn't use (or even modify) it - it's licensed under NonCommercial CC, and my project is a commercial one.

So I had to write my own code which I would like to share with other's (dual-licensed under MPL 1.1 and LGPL 2.1).

Usage of HttpPostData-class: <Update April 1st 2010>I had an error in this text for a half year and nobody noticed? Strange...</Update>

  1. Create an Instance of HttpPostData:
var postData:HttpPostData = new HttpPostData()
  1. Add your parameters and file attachments
postData.addParameter('foo1', 'bar1'); // POST-Field 'foo1' has value 'bar1'
postData.addParameter('foo2', 'bar2'); // POST-Field 'foo2' has value 'bar2'

// POST-Field 'uploadedFile1' contains someBinaryData1 (ByteArray)
// as 'application/octet-stream' with filename 'uploadedFile1'
postData.addFile('uploadedFile1', someBinaryData1);

// POST-Field 'uploadedFile2' contains someBinaryData2 (ByteArray)
// as 'image/png' with filename 'image.png'
postData.addFile('uploadedFile2', someBinaryData2, 'image.png', 'image/png')
  1. Close this object. This will append the ending boundary to the data which makes it impossible to add additional form data.
postData.close();
  1. Bind this to an URLRequest
var request:URLRequest = new URLRequest("http://www.example.org/someDestination/");
postData.bind(request)
  1. Send the request
var urlLoader:URLLoader = new URLLoader();
urlLoader.load(request);

Have fun!

Java: Model-View-Controller without memory leaks

Published by cybso on

This is a post from my original site, which was hosted by the former blog service of the University of Osnabrück. I have moved it to the new site for archiving. Pages linked in this article may no longer work today, and the blog comments under the article no longer exist. Opinions expressed in this article reflect the point of view of the time of publication and do not necessarily reflect my opinion today.

When doing MVC programming in Java, there is a problem that most people don't know about. I've ignored it myself much too long. The problem is that when you bind a model class to an UI component you will get a giant memory leak.

What happens?

Well, imagine a model class supporting listening for property changes. A simple example might look like this (I extend from PropertyChangeSupport here so that I don't have to delegate all the methods, normally you wouldn't do so, of course):

public class Model extends PropertyChangeSupport {
    private String name;
    public Model(String name) {
        super(new Object()); // Only an example! Don't do this in RL!
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        firePropertyChange("name", this.name, this.name = name);
    }
}

Next, imagine a view for this model class. It has an input field that is binded in both direction with the model (very simplified example here, I normally don't code this way ;-)):

public class ModelView extends JPanel {
    public ModelView(final Model model) {
        super(new BorderLayout());
        add(new JLabel("Name: "), BorderLayout.WEST);

        final JTextField textfield = new JTextField(model.getName());
        add(textfield, BorderLayout.CENTER);

        // Bind textfield => model (harmless)
        textfield.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                model.setName(textfield.getText());
            }
        });

        // Bind model => textfield (introduces memory leak)
        model.addPropertyChangeListener("name", new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent e) {
                textfield.setText(model.getName());
            }
        });
    }
}

From now on we have a memory leak, because the JPanel, the JLabel and the JTextField (and all other referenced) objects will never be removed by the garbage collector as long as the model exists (which might be until the applications end of life). The reason is that the anonymous inner PropertyChangeListener instance has (and must have!) an implicit reference to the JPanel. And even if you replace it by a static class it does have to know the textfield which is a child object of the panel and has a reference back to it. So even if nobody else references the panel the garbage collector sees:

  Model => PropertyChangeListener => JPanel

There is a little known class called WeakReference (and his brother WeakHashMap). It contains an object, but the object could still be removed by the garbage collector as long as there is no other (non-weak) reference to it.

A naive idea is to just encapsulate the PropertyChangeListener within a WeakReference object:

public class WeakListener implements PropertyChangeListener {
    private final WeakReference<PropertyChangeListener> listener;
    public WeakListener(PropertyChangeListener listener) {
        this.listener = new WeakReference<PropertyChangeListener>(listener);
    }

    public void propertyChange(PropertyChangeEvent e) {
        PropertyChangeListener l = this.listener.get();
        if (l != null) {
            l.propertyChange(e);
        }
    }
}

Code in ModelView constructor:

// Bind model => textfield (with little memory leak)
model.addPropertyChangeListener("name", new WeakListener(new PropertyChangeListener() {
    public void propertyChange(PropertyChangeEvent e) {
        textfield.setText(model.getName());
    }
}));

The idea is that you still have this simple and small WeakListener object within your model's listener list, but the really big part (the original listener, the panel, label, textfield, etc) could be free'd. Sadly, this will not work, because as soon as you gave the anonymous PropertyChangeListener to WeakListener's constructor nobody else does reference to it, so the garbage collector will remove the object immediately.

The trick is to create a single reference to it which belongs the parent object:

public class ModelView extends JPanel {
    private PropertyChangeListener modelTextfieldListener;

    public ModelView(final Model model) {
        super(new BorderLayout());
        add(new JLabel("Name: "), BorderLayout.WEST);

        final JTextField textfield = new JTextField(model.getName());
        add(textfield, BorderLayout.CENTER);

        // Bind textfield => model (harmless)
        textfield.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                model.setName(textfield.getText());
            }
        });

        // Bind model => textfield (with little memory leak)
        model.addPropertyChangeListener("name", new WeakListener(modelTextfieldListener = new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent e) {
                textfield.setText(model.getName());
            }
        }));
    }
}

That's it. To make this easier I've created a little support class WeakListenerSupport that's very helpful if you have to deal with multiple input-property-bindings. Also it tries to remove ("unlink") itself from the model if the listener doesn't exist any longer. It even allows to unlink all weak listeners from a single object.

With this class the above example would look like:

public class ModelView extends JPanel {
    private final WeakListenerSupport wls = new WeakListenerSupport();

    public ModelView(final Model model) {
        super(new BorderLayout());
        add(new JLabel("Name: "), BorderLayout.WEST);

        final JTextField textfield = new JTextField(model.getName());
        add(textfield, BorderLayout.CENTER);

        // Bind textfield => model (harmless)
        textfield.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                model.setName(textfield.getText());
            }
        });

        // Bind model => textfield (without memory leak)
        model.addPropertyChangeListener("name", wls.propertyChange(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent e) {
                textfield.setText(model.getName());
            }
        }, model));
    }
}

JTextPane with background color

Published by cybso on

This is a post from my original site, which was hosted by the former blog service of the University of Osnabrück. I have moved it to the new site for archiving. Pages linked in this article may no longer work today, and the blog comments under the article no longer exist. Opinions expressed in this article reflect the point of view of the time of publication and do not necessarily reflect my opinion today.

JTextPane and his ancestors JEditorPane and JTextComponent won't respect the color defined with setBackground(Color) since they display a "styled document" and expect the background color to be defined in the content. You'll always see a white background.

To change the background color (without modifying the content) you have to define attributes for the document:

JTextPane textPane = new JTextPane();
textPane.setContentType("text/html"); // or any other styled content type
textPane.setText("White text on a red background");

textPane.setForeground(Color.white); // Works as expected
textPane.setBackground(Color.red); // Obsolete, no affect

// Define a default background color attribute
Color backgroundColor = Color.red;
SimpleAttributeSet background = new SimpleAttributeSet();
StyleConstants.setBackground(background, backgroundColor);
textPane.getStyledDocument().setParagraphAttributes(0,
        textPane.getDocument().getLength(), background, false);

// And remove default (white) margin
textPane.setBorder(BorderFactory.createEmptyBorder());

// Alternative: Leave a 2px border but draw it in the same color
textPane.setBorder(BorderFactory.createLineBorder(backgroundColor, 2));