StructureMap using named instance during initialize in scanned assemblies in ASP.Net MVC4

I work on a project which use StructureMap as dependency injection manager in a C# Asp.Net MVC4 context.

Basically the structure of the project is a library project (we’ll call it Assembly 1) and a Web project (we’ll call it Assembly 2) which references the library project.

At some point I needed to register named instances in structuremap in the library project Assembly 1 and then use them in the web project Assembly 2.

If you’re in hurry here the working answer in order to have everything working without explanations:


//Assembly 1
public class MyRegistry : Registry
{
    private MyRegistry()
    {
        For().Add(new MyStuff()).Named("myInstance");           
    }
    public static void Setup()
    {
        MyRegistry initializer = new MyRegistry();
        ObjectFactory.Initialize(x =>
        {
            x.AddRegistry(initializer);
            x.Scan(y =>
            {
                y.AssembliesFromApplicationBaseDirectory();
                y.LookForRegistries();
            });

        });
    }       
}

//Assembly 2
public class MySubRegistry : Registry
{
    public Initializer()
    {
        //For().Use().Ctor("config").Is(ObjectFactory.GetNamedInstance("myInstance"));//Doesn't work
        For().Use().Ctor("config").Is(x => x.ConstructedBy(y => ObjectFactory.GetNamedInstance("myInstance")));//This work
    }       
}

Long(er) version

So you want to register named instances in the main registry, you want to use them in some other registries in a sub-assembly and you want to register other stuff in your sub-registry.

An approach could be to scan other assemblies after the container is initialized (example below).


//Assembly 1
public class MyRegistry : Registry
{
    private MyRegistry()
    {
        For().Add(new MyStuff()).Named("myInstance");           
    }
    public static void Setup()
    {
        MyRegistry initializer = new MyRegistry();
        ObjectFactory.Initialize(x =>
        {
            x.AddRegistry(initializer);
        });
        initializer.Scan(y =>
        {
            y.AssembliesFromApplicationBaseDirectory();
            y.LookForRegistries();
        });
    }       
}

This might works for you to use named instances elsewhere in your project but, from a bad experience I had, if after you add some instances (named or not) of some interfaces in a scanned registry they will not be registered.


//Assembly 2
public class MySubRegistry : Registry
{
    public Initializer()
    {
        //With the scan made outside the initialize the named instance can be retrieved as structuremap is already initialized
        For().Use().Ctor("config").Is(ObjectFactory.GetNamedInstance("myInstance"));
        //But this one will never be registered as structure is already initialized
        For().Add(new MyObject());
    }       
}

Thus the only way in order to have everything works is (as described at the top of this article) to scan other registries at structuremap initialisation time AND in scanned registries to use delegate to access things registered in the main registry.


//This
For().Use().Ctor("config").Is(x => x.ConstructedBy(y => ObjectFactory.GetNamedInstance("myInstance")));
//Instead of
For().Use().Ctor("config").Is(ObjectFactory.GetNamedInstance("myInstance"));

Indeed the delegate here will be lazy evaluated. So when it will be evaluated everything would have been registered.
This is really tricky, it worked for me and I hope it will work for you as well.

If you have question or something to fix in the code of this article feel free to comment 🙂

Posted in asp.net, C# | Tagged , , , | Leave a comment

Using Gmail smtp through VPN (on Synology)

I use my Synology NAS with a VPN which is always connected. In response to some events I wanted to send custom email notifications (btw if you are interested in this part I recommend this excellent article Send Custom (email) Notifications from scripts running on a Synology).

I use the Gmail’s smtp server with one of my email.
In general there are several things you need to do to make it work:

  1. Ask your vpn provider to whitelist the ip of the gmail smtp you resolve once connected (to get the ip you resolve from vpn: ssh/telnet to your nas with root user and ping -4 smtp.gmail.com). Indeed most providers block smtp in order to prevent spams. My provider (privateinternetaccess) has whitelisted the ip in 24h
  2. Fill the ip in the notification panel (as on the picture)
  3. Send a test mail
  4. If you receive a mail from Google saying your account might have been hacked log on gmail, then go to https://accounts.google.com/DisplayUnlockCaptcha and send a test mail again

Synology notification panel

It now should works! Hope it has helped 🙂

Posted in tutorial, vpn | Tagged , , ,

Generate ASP classes

I wrote a simple python script in order to generate some ASP (classic not dot net) classes:
Here it is as it:

# -*- coding: windows-1252 -*-
# @author: RaphaĂŤl Beck
# ex: >> python generateAspClass.py -n Country -f code -f name -f id > Country.asp

import os
import string
import re
from collections import defaultdict
from optparse import OptionParser
from datetime import datetime

name = None


baseStruc = """<%%
' -----------------------------------------------------------------------------
' @File   : /%(name)s.asp
' @Desc   : %(name)s
' @Create : %(date)s
' @Author : R.BECK
' -----------------------------------------------------------------------------
class %(name)s

%(fields)s
    
    ' Constructor
    Private Sub Class_Initialize()
%(init_fields)s
    end sub
    
    ' Destructor    
    'Private Sub Class_Terminate()    
    'end sub
    
    'Getters
    %(getters)s
    
    ' Setters
    %(setters)s

end class
%%>
"""

field_format = "\tprivate %(private_field_name)s\n"

getter_format = """
    Public property get %(field_name)s    
        %(field_name)s = %(private_field_name)s
    End Property
"""

setter_format = """
    Public property let %(field_name)s(p_%(field_name)s)  
        %(private_field_name)s = p_%(field_name)s
    End Property
"""

init_format = """\t\t%(private_field_name)s = 0"""

if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option("-f", "--fields",
                      action="append", dest="fields", default=[],
                      help="Class' fields")

    parser.add_option("-n", "--name", dest="name", 
                      help="Class' name")
                      
    (options, args) = parser.parse_args()
    
    if not options.name:
        print "The name of the class is mandatory"
        exit(-1)
    name = options.name
    
    private_fields = []
    getters = []
    setters = []
    init_fields = []

    for field_name in set(options.fields):
        field_dict = {"field_name": field_name, "private_field_name": "m_%s" % field_name}
        private_fields.append(field_format % field_dict)
        getters.append(getter_format % field_dict)
        setters.append(setter_format % field_dict)
        init_fields.append(init_format % field_dict)
    
    date = datetime.now()
    dateStr = "%s/%s/%s" % (date.day, date.month, date.year)
    
    print baseStruc % {
        "name": name,
        "fields": "".join(private_fields),
        "getters": "\n".join(getters),
        "setters": "\n".join(setters),
        "date": dateStr,
        "init_fields": "\n".join(init_fields),
    }
    
    
    
    
    
    

Usage:

python generateAspClass.py -n Country -f code -f name -f id > Country.asp

You can use the code, modify it (I’ll be happy to see your modifications, in case I have forgotten something) and distribute it (it’ll be great if you link to this site :D).

Posted in asp, python | Tagged , | Leave a comment

Working with IE7, jQuery and Forms

If you just want the solution skip the context

Context

For my work I had to make a register form from where the user had to send three separate files.

The non-javascript version is a simple form with three input file, like the following:

<form enctype="multipart/form-data" id="formMain">
  <input type="file" name="file1" />
  <input type="file" name="file2" />
  <input type="file" name="file3" />
  <button type="submit">Submit</button>
</form>

However the javascript version (meaning javascript enabled in the browser) had to have an “add” button next to each input so the chosen solution was to change at the loading time the structure of the form for this one:

<form enctype="multipart/form-data" target="iframe1" id="form1">
 <input type="file" name="file1"/>
 <button type="submit">Add</button>
</form>
<iframe class="hidden" onLoad="iframeLoaded(this);" id="iframe1" name="iframe1"/>

The purpose of the iframe is to upload the file without reloading the page. The user select a file, hit the add button and then the form will be submitted to the iframe thanks to the “target” attribute. When the iframe will be loaded it’ll return some json and the iframeLoaded function will manage the state of the page (depending if there were an error like file too big or else).

So, let’s make this structure with the previous form:

//Unwrap the main form
$("#formMain").replaceWith($("#formMain").contents()); 
//Creating the new form
var $newForm1 = $("<form/>").attr({"enctype":"multipart/form-data", "target":"iframe1", "id":"form1"});
//Wrapping the first input with the new form
$("input[type=file][name=file1]").wrap($newForm1);
//Creating the add button and adding to the form
$("<button/>").attr({"type":"submit"}).appendTo($newForm1);
//Creating the iframe, binding the onLoad event and appending it next to the form
$("<iframe/>").attr({"class":"hidden", "id":"iframe1", "name":"iframe1"}).appendTo($newForm1.parent()).on("load", function(){/*do your stuff*/});

Ok so you open your favorite browser (meaning a modern browser like chrome), you test it works! (Normally :D)

Then you open Internet Explorer because yes your agency has accepted the customer minimal requirement of IE7+ and it doesn’t work ! Why?

Solution

If you want to create (on-the-fly) forms and they work with IE7 you have to:

  • Write $(“<form></form>”) instead of $(“<form/>”). Both instructions are valid in all browsers but IE7. I don’t know why..
  • Change the name (put one if you haven’t) of the form every time you change its place in the page with something like $newForm1.attr(“name”, “newForm1″+(Math.floor(Math.random()*1000)));
  • More specific to my context the “.on(“load”, callback)” or “.load(callback)” doesn’t really work on iframeS in IE7 so you have to declare your iframe with the onLoad attribute at the generation time of the page.
Posted in tips, web | Tagged , , , | Leave a comment

Two bookmarklet for testing your responsive design

What really is a bookmarlet? 
Basically a bookmarklet is JavaScript code embedded in a web link. Generally they call an external JavaScript file/library in order to add features to your current browsed web page. The advantage of these is that you just have to drag the link into your bookmark bar and every time you hit it some features appears on your page. So, no plugin, browser-independent and if you sync your bookmarks you will have it in all your browsers on every machine you have. A more complete explanation about bookmarklets are available on wikipedia.

I have started to used bookmarklet for a while now, they are very useful only one click on your bookmark bar and *bam*you have access to great features without having any plugin installed. I use particularly two bookmarklets for testing my responsive designs.

Responsive design test bookmarklet

Available here

I have taken http://bradfrostweb.com/demo/mobile-first/ as exemple, here are the “regular” desktop version.

Once the bookmarlet is actived a nice toolbar appears on the top and you can switch between possible views. Here in portait tablet size:

and here in portrait mobile size:

Resizer // A responsive design bookmarklet

Available here

The second one is basically the same thing but it can be useful to have a look if you don’t know how to add bookmarklets to your browser.

Enjoy testing your responsive design 🙂

Posted in Uncategorized | Leave a comment

Defaults drawable(s) in Android

Recently I have begun to play with Android, for one of my project I wanted to use some default images embedded in the framework. I have found the page of the documentation with these images but there is no visual preview of images. So I have made a little application which displays all of these icons. I though it could be a good training and might be useful (for me at least).

Here is what the application will look like:

Image

There is nothing special about it just a simple GridView with a TextView and an ImageView for each row.

For this application only four files (in addition to standard ones) are required:

  • main.xml this will be our main layout which contains the GridView
  • DrawingTestActivity.java this will be our main activity
  • gridrow.xml this will be the layout of each row
  • GridAdapter.java which will be the adapter for the grid used
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

 <!-- The grid view -->
 <GridView
    android:id="@+id/gridViewMain"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:numColumns="auto_fit">

</GridView>

</LinearLayout>

 

DrawingTestActivity.java:
package com.rphbck;

import android.app.Activity;
import android.os.Bundle;
import android.widget.GridView;

public class DrawingTestActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //We set the layout
        setContentView(R.layout.main);

        //We get the GridView by its id
        GridView gridview = (GridView) findViewById(R.id.gridViewMain);

        //We set the GridAdapter to the gridview
        gridview.setAdapter(new GridAdapter(this));
    }
}
We need to set an adapter to the GridView to tell it how to display. There are some standard ones but here we want to use our own.

 

gridrow.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >

 <TextView
    android:id="@+id/draw_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingBottom="50dip"/>

 <LinearLayout android:id="@+id/thumbnail"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="15dip"
    android:layout_alignParentLeft="true">

    <ImageView
        android:id="@+id/draw_image"
        android:layout_width="50dip"
        android:layout_height="50dip" />

 </LinearLayout>
</RelativeLayout>
We use for one row layout a TextView to display the name of the drawable property and an ImageView to display it as an image.

 

GridAdapter.java:
And finally we make our grid adapter
package com.rphbck;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class GridAdapter extends BaseAdapter {//Don't forget to extends BaseAdapter

 private Context mContext; //The context of the application
 private static LayoutInflater mInflater=null; //A helper for setting a layout from the code
 private ArrayList mThumbsLabels; //The list of our labels
 private ArrayList mThumbsValues; //The list of our image references

 public GridAdapter(Context c) {
  mContext = c;
  mThumbsLabels = new ArrayList();
  mThumbsValues = new ArrayList();

  //We populate our arrays
  for (Map.Entry entry : mThumbs.entrySet()) {
    mThumbsLabels.add(entry.getKey());
    mThumbsValues.add(entry.getValue());
  }
  //We get the layout manager
  mInflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 }

 @Override
 public int getCount() {
  return mThumbs.size();
 }

 @Override
 public Object getItem(int arg0) {
  return null;
 }

 @Override
 public long getItemId(int arg0) {
  return 0;
 }

 //Here is our important function to set every row of the gridview
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  String label = mThumbsLabels.get(position);//We get the current drawable name
  Integer value = mThumbsValues.get(position);//We get the current drawable value
  View vi=convertView;

  // if it's not recycled, initialize some attributes
  if(convertView==null) vi = mInflater.inflate(R.layout.gridrow, parent, false);
 //We search the text view and the image view
  TextView tvLabel = (TextView) vi.findViewById(R.id.draw_name);
  ImageView ivValue = (ImageView) vi.findViewById(R.id.draw_image);
 //And we set their attributes
  tvLabel.setText(label);
  ivValue.setImageResource(value);

  return vi;
 }

//Here is the list of default system drawables. The key is only for displaying purposes and the value is the reference to the drawable
 private HashMap mThumbs = new HashMap(){{
	put("android.R.drawable.alert_dark_frame", android.R.drawable.alert_dark_frame);
	put("android.R.drawable.alert_light_frame", android.R.drawable.alert_light_frame);
	put("android.R.drawable.arrow_down_float", android.R.drawable.arrow_down_float);
	put("android.R.drawable.arrow_up_float", android.R.drawable.arrow_up_float);
	put("android.R.drawable.bottom_bar", android.R.drawable.bottom_bar);
	put("android.R.drawable.btn_default", android.R.drawable.btn_default);
	put("android.R.drawable.btn_default_small", android.R.drawable.btn_default_small);
	put("android.R.drawable.btn_dialog", android.R.drawable.btn_dialog);
	put("android.R.drawable.btn_dropdown", android.R.drawable.btn_dropdown);
	put("android.R.drawable.btn_minus", android.R.drawable.btn_minus);
	put("android.R.drawable.btn_plus", android.R.drawable.btn_plus);
	put("android.R.drawable.btn_radio", android.R.drawable.btn_radio);
	put("android.R.drawable.btn_star", android.R.drawable.btn_star);
	put("android.R.drawable.btn_star_big_off", android.R.drawable.btn_star_big_off);
	put("android.R.drawable.btn_star_big_on", android.R.drawable.btn_star_big_on);
	put("android.R.drawable.button_onoff_indicator_off", android.R.drawable.button_onoff_indicator_off);
	put("android.R.drawable.button_onoff_indicator_on", android.R.drawable.button_onoff_indicator_on);
	put("android.R.drawable.checkbox_off_background", android.R.drawable.checkbox_off_background);
	put("android.R.drawable.checkbox_on_background", android.R.drawable.checkbox_on_background);
	put("android.R.drawable.dark_header", android.R.drawable.dark_header);
	put("android.R.drawable.dialog_frame", android.R.drawable.dialog_frame);
	put("android.R.drawable.dialog_holo_dark_frame", android.R.drawable.dialog_holo_dark_frame);
	put("android.R.drawable.dialog_holo_light_frame", android.R.drawable.dialog_holo_light_frame);
	put("android.R.drawable.divider_horizontal_bright", android.R.drawable.divider_horizontal_bright);
	put("android.R.drawable.divider_horizontal_dark", android.R.drawable.divider_horizontal_dark);
	put("android.R.drawable.divider_horizontal_dim_dark", android.R.drawable.divider_horizontal_dim_dark);
	put("android.R.drawable.divider_horizontal_textfield", android.R.drawable.divider_horizontal_textfield);
	put("android.R.drawable.edit_text", android.R.drawable.edit_text);
	put("android.R.drawable.editbox_background", android.R.drawable.editbox_background);
	put("android.R.drawable.editbox_background_normal", android.R.drawable.editbox_background_normal);
	put("android.R.drawable.editbox_dropdown_dark_frame", android.R.drawable.editbox_dropdown_dark_frame);
	put("android.R.drawable.editbox_dropdown_light_frame", android.R.drawable.editbox_dropdown_light_frame);
	put("android.R.drawable.gallery_thumb", android.R.drawable.gallery_thumb);
	put("android.R.drawable.ic_btn_speak_now", android.R.drawable.ic_btn_speak_now);
	put("android.R.drawable.ic_delete", android.R.drawable.ic_delete);
	put("android.R.drawable.ic_dialog_alert", android.R.drawable.ic_dialog_alert);
	put("android.R.drawable.ic_dialog_dialer", android.R.drawable.ic_dialog_dialer);
	put("android.R.drawable.ic_dialog_email", android.R.drawable.ic_dialog_email);
	put("android.R.drawable.ic_dialog_info", android.R.drawable.ic_dialog_info);
	put("android.R.drawable.ic_dialog_map", android.R.drawable.ic_dialog_map);
	put("android.R.drawable.ic_input_add", android.R.drawable.ic_input_add);
	put("android.R.drawable.ic_input_delete", android.R.drawable.ic_input_delete);
	put("android.R.drawable.ic_input_get", android.R.drawable.ic_input_get);
	put("android.R.drawable.ic_lock_idle_alarm", android.R.drawable.ic_lock_idle_alarm);
	put("android.R.drawable.ic_lock_idle_charging", android.R.drawable.ic_lock_idle_charging);
	put("android.R.drawable.ic_lock_idle_lock", android.R.drawable.ic_lock_idle_lock);
	put("android.R.drawable.ic_lock_idle_low_battery", android.R.drawable.ic_lock_idle_low_battery);
	put("android.R.drawable.ic_lock_lock", android.R.drawable.ic_lock_lock);
	put("android.R.drawable.ic_lock_power_off", android.R.drawable.ic_lock_power_off);
	put("android.R.drawable.ic_lock_silent_mode", android.R.drawable.ic_lock_silent_mode);
	put("android.R.drawable.ic_lock_silent_mode_off", android.R.drawable.ic_lock_silent_mode_off);
	put("android.R.drawable.ic_media_ff", android.R.drawable.ic_media_ff);
	put("android.R.drawable.ic_media_next", android.R.drawable.ic_media_next);
	put("android.R.drawable.ic_media_pause", android.R.drawable.ic_media_pause);
	put("android.R.drawable.ic_media_play", android.R.drawable.ic_media_play);
	put("android.R.drawable.ic_media_previous", android.R.drawable.ic_media_previous);
	put("android.R.drawable.ic_media_rew", android.R.drawable.ic_media_rew);
	put("android.R.drawable.ic_menu_add", android.R.drawable.ic_menu_add);
	put("android.R.drawable.ic_menu_agenda", android.R.drawable.ic_menu_agenda);
	put("android.R.drawable.ic_menu_always_landscape_portrait", android.R.drawable.ic_menu_always_landscape_portrait);
	put("android.R.drawable.ic_menu_call", android.R.drawable.ic_menu_call);
	put("android.R.drawable.ic_menu_camera", android.R.drawable.ic_menu_camera);
	put("android.R.drawable.ic_menu_close_clear_cancel", android.R.drawable.ic_menu_close_clear_cancel);
	put("android.R.drawable.ic_menu_compass", android.R.drawable.ic_menu_compass);
	put("android.R.drawable.ic_menu_crop", android.R.drawable.ic_menu_crop);
	put("android.R.drawable.ic_menu_day", android.R.drawable.ic_menu_day);
	put("android.R.drawable.ic_menu_delete", android.R.drawable.ic_menu_delete);
	put("android.R.drawable.ic_menu_directions", android.R.drawable.ic_menu_directions);
	put("android.R.drawable.ic_menu_edit", android.R.drawable.ic_menu_edit);
	put("android.R.drawable.ic_menu_gallery", android.R.drawable.ic_menu_gallery);
	put("android.R.drawable.ic_menu_help", android.R.drawable.ic_menu_help);
	put("android.R.drawable.ic_menu_info_details", android.R.drawable.ic_menu_info_details);
	put("android.R.drawable.ic_menu_manage", android.R.drawable.ic_menu_manage);
	put("android.R.drawable.ic_menu_mapmode", android.R.drawable.ic_menu_mapmode);
	put("android.R.drawable.ic_menu_month", android.R.drawable.ic_menu_month);
	put("android.R.drawable.ic_menu_more", android.R.drawable.ic_menu_more);
	put("android.R.drawable.ic_menu_my_calendar", android.R.drawable.ic_menu_my_calendar);
	put("android.R.drawable.ic_menu_mylocation", android.R.drawable.ic_menu_mylocation);
	put("android.R.drawable.ic_menu_myplaces", android.R.drawable.ic_menu_myplaces);
	put("android.R.drawable.ic_menu_preferences", android.R.drawable.ic_menu_preferences);
	put("android.R.drawable.ic_menu_recent_history", android.R.drawable.ic_menu_recent_history);
	put("android.R.drawable.ic_menu_report_image", android.R.drawable.ic_menu_report_image);
	put("android.R.drawable.ic_menu_revert", android.R.drawable.ic_menu_revert);
	put("android.R.drawable.ic_menu_rotate", android.R.drawable.ic_menu_rotate);
	put("android.R.drawable.ic_menu_save", android.R.drawable.ic_menu_save);
	put("android.R.drawable.ic_menu_search", android.R.drawable.ic_menu_search);
	put("android.R.drawable.ic_menu_send", android.R.drawable.ic_menu_send);
	put("android.R.drawable.ic_menu_set_as", android.R.drawable.ic_menu_set_as);
	put("android.R.drawable.ic_menu_share", android.R.drawable.ic_menu_share);
	put("android.R.drawable.ic_menu_slideshow", android.R.drawable.ic_menu_slideshow);
	put("android.R.drawable.ic_menu_sort_alphabetically", android.R.drawable.ic_menu_sort_alphabetically);
	put("android.R.drawable.ic_menu_sort_by_size", android.R.drawable.ic_menu_sort_by_size);
	put("android.R.drawable.ic_menu_today", android.R.drawable.ic_menu_today);
	put("android.R.drawable.ic_menu_upload", android.R.drawable.ic_menu_upload);
	put("android.R.drawable.ic_menu_upload_you_tube", android.R.drawable.ic_menu_upload_you_tube);
	put("android.R.drawable.ic_menu_view", android.R.drawable.ic_menu_view);
	put("android.R.drawable.ic_menu_week", android.R.drawable.ic_menu_week);
	put("android.R.drawable.ic_menu_zoom", android.R.drawable.ic_menu_zoom);
	put("android.R.drawable.ic_notification_clear_all", android.R.drawable.ic_notification_clear_all);
	put("android.R.drawable.ic_notification_overlay", android.R.drawable.ic_notification_overlay);
	put("android.R.drawable.ic_partial_secure", android.R.drawable.ic_partial_secure);
	put("android.R.drawable.ic_popup_disk_full", android.R.drawable.ic_popup_disk_full);
	put("android.R.drawable.ic_popup_reminder", android.R.drawable.ic_popup_reminder);
	put("android.R.drawable.ic_popup_sync", android.R.drawable.ic_popup_sync);
	put("android.R.drawable.ic_search_category_default", android.R.drawable.ic_search_category_default);
	put("android.R.drawable.ic_secure", android.R.drawable.ic_secure);
	put("android.R.drawable.list_selector_background", android.R.drawable.list_selector_background);
	put("android.R.drawable.menu_frame", android.R.drawable.menu_frame);
	put("android.R.drawable.menu_full_frame", android.R.drawable.menu_full_frame);
	put("android.R.drawable.menuitem_background", android.R.drawable.menuitem_background);
	put("android.R.drawable.picture_frame", android.R.drawable.picture_frame);
	put("android.R.drawable.presence_audio_away", android.R.drawable.presence_audio_away);
	put("android.R.drawable.presence_audio_busy", android.R.drawable.presence_audio_busy);
	put("android.R.drawable.presence_audio_online", android.R.drawable.presence_audio_online);
	put("android.R.drawable.presence_away", android.R.drawable.presence_away);
	put("android.R.drawable.presence_busy", android.R.drawable.presence_busy);
	put("android.R.drawable.presence_invisible", android.R.drawable.presence_invisible);
	put("android.R.drawable.presence_offline", android.R.drawable.presence_offline);
	put("android.R.drawable.presence_online", android.R.drawable.presence_online);
	put("android.R.drawable.presence_video_away", android.R.drawable.presence_video_away);
	put("android.R.drawable.presence_video_busy", android.R.drawable.presence_video_busy);
	put("android.R.drawable.presence_video_online", android.R.drawable.presence_video_online);
	put("android.R.drawable.progress_horizontal", android.R.drawable.progress_horizontal);
	put("android.R.drawable.progress_indeterminate_horizontal", android.R.drawable.progress_indeterminate_horizontal);
	put("android.R.drawable.radiobutton_off_background", android.R.drawable.radiobutton_off_background);
	put("android.R.drawable.radiobutton_on_background", android.R.drawable.radiobutton_on_background);
	put("android.R.drawable.screen_background_dark", android.R.drawable.screen_background_dark);
	put("android.R.drawable.screen_background_dark_transparent", android.R.drawable.screen_background_dark_transparent);
	put("android.R.drawable.screen_background_light", android.R.drawable.screen_background_light);
	put("android.R.drawable.screen_background_light_transparent", android.R.drawable.screen_background_light_transparent);
	put("android.R.drawable.spinner_background", android.R.drawable.spinner_background);
	put("android.R.drawable.spinner_dropdown_background", android.R.drawable.spinner_dropdown_background);
	put("android.R.drawable.star_big_off", android.R.drawable.star_big_off);
	put("android.R.drawable.star_big_on", android.R.drawable.star_big_on);
	put("android.R.drawable.star_off", android.R.drawable.star_off);
	put("android.R.drawable.star_on", android.R.drawable.star_on);
	put("android.R.drawable.stat_notify_call_mute", android.R.drawable.stat_notify_call_mute);
	put("android.R.drawable.stat_notify_chat", android.R.drawable.stat_notify_chat);
	put("android.R.drawable.stat_notify_error", android.R.drawable.stat_notify_error);
	put("android.R.drawable.stat_notify_missed_call", android.R.drawable.stat_notify_missed_call);
	put("android.R.drawable.stat_notify_more", android.R.drawable.stat_notify_more);
	put("android.R.drawable.stat_notify_sdcard", android.R.drawable.stat_notify_sdcard);
	put("android.R.drawable.stat_notify_sdcard_prepare", android.R.drawable.stat_notify_sdcard_prepare);
	put("android.R.drawable.stat_notify_sdcard_usb", android.R.drawable.stat_notify_sdcard_usb);
	put("android.R.drawable.stat_notify_sync", android.R.drawable.stat_notify_sync);
	put("android.R.drawable.stat_notify_sync_noanim", android.R.drawable.stat_notify_sync_noanim);
	put("android.R.drawable.stat_notify_voicemail", android.R.drawable.stat_notify_voicemail);
	put("android.R.drawable.stat_sys_data_bluetooth", android.R.drawable.stat_sys_data_bluetooth);
	put("android.R.drawable.stat_sys_download", android.R.drawable.stat_sys_download);
	put("android.R.drawable.stat_sys_download_done", android.R.drawable.stat_sys_download_done);
	put("android.R.drawable.stat_sys_headset", android.R.drawable.stat_sys_headset);
	put("android.R.drawable.stat_sys_phone_call", android.R.drawable.stat_sys_phone_call);
	put("android.R.drawable.stat_sys_phone_call_forward", android.R.drawable.stat_sys_phone_call_forward);
	put("android.R.drawable.stat_sys_phone_call_on_hold", android.R.drawable.stat_sys_phone_call_on_hold);
	put("android.R.drawable.stat_sys_speakerphone", android.R.drawable.stat_sys_speakerphone);
	put("android.R.drawable.stat_sys_upload", android.R.drawable.stat_sys_upload);
	put("android.R.drawable.stat_sys_upload_done", android.R.drawable.stat_sys_upload_done);
	put("android.R.drawable.stat_sys_vp_phone_call", android.R.drawable.stat_sys_vp_phone_call);
	put("android.R.drawable.stat_sys_vp_phone_call_on_hold", android.R.drawable.stat_sys_vp_phone_call_on_hold);
	put("android.R.drawable.stat_sys_warning", android.R.drawable.stat_sys_warning);
	put("android.R.drawable.status_bar_item_app_background", android.R.drawable.status_bar_item_app_background);
	put("android.R.drawable.status_bar_item_background", android.R.drawable.status_bar_item_background);
	put("android.R.drawable.sym_action_call", android.R.drawable.sym_action_call);
	put("android.R.drawable.sym_action_chat", android.R.drawable.sym_action_chat);
	put("android.R.drawable.sym_action_email", android.R.drawable.sym_action_email);
	put("android.R.drawable.sym_call_incoming", android.R.drawable.sym_call_incoming);
	put("android.R.drawable.sym_call_missed", android.R.drawable.sym_call_missed);
	put("android.R.drawable.sym_call_outgoing", android.R.drawable.sym_call_outgoing);
	put("android.R.drawable.sym_contact_card", android.R.drawable.sym_contact_card);
	put("android.R.drawable.sym_def_app_icon", android.R.drawable.sym_def_app_icon);
	put("android.R.drawable.title_bar", android.R.drawable.title_bar);
	put("android.R.drawable.title_bar_tall", android.R.drawable.title_bar_tall);
	put("android.R.drawable.toast_frame", android.R.drawable.toast_frame);
	put("android.R.drawable.zoom_plate", android.R.drawable.zoom_plate);
 }};

}
You can find the final (unsigned) apk here, just think to remove the png extension that I’ve added because of wordpress.
Posted in Android, tutorial | Tagged , | Leave a comment

How contribute_to_model can handle ManyToMany fields ?

I work on a crm made in django (cremecrm.com), and sometimes for customers I use the snippet contribute_to_model in order to avoid to modify existing models. It’s the best solution we found for staying the most mainstream and avoid huge merges. The problem with this work around is it doesn’t handle many to many. Here’s the tip I found for managing m2m without modifying contribute to model.

The tips to deal with many to many :

# -*- coding: utf-8 -*-

from django.db import models
from django.db.models.fields import CharField, BooleanField
from django.db.models.fields.related import ManyToManyField
from django.utils.translation import ugettext_lazy as _

from contribute_to_model import contribute_to_model

class MyModel(models.Model):
    title = CharField(_(u'Title'), max_length=100)

    class Meta:
        app_label = "my_app"

class MyFutureM2MModel(models.Model):
    foo = CharField(_(u'Foo'), max_length=100)

    class Meta:
        app_label = "my_app"

class MyModelWhichContribute(models.Model):
    field_to_add1 = CharField(_(u'field_to_add1 to MyModel'), max_length=100, blank=True, null=True)
    field_to_add2 = BooleanField(_(u'field_to_add2 to MyModel'), default=False)

    class Meta:
        abstract = True
        db_table = 'my_app_mymodel'

MyModel.add_to_class('my_m2m_field_name', ManyToManyField(MyFutureM2MModel, verbose_name=_(u'My m2m'), blank=True, null=True))
contribute_to_model(MyModelWhichContribute, MyModel)

The contribute_to_model code (which is not from me):


from django.db import models
from django.utils.functional import curry


def contribute_to_model(contrib, destination):
    """
    Update ``contrib`` model based on ``destination``.

    Every new field will be created. Existing fields will have some properties
    updated.

    Methods and properties of ``contrib`` will populate ``destination``.

    Usage example:

    >>> from django.contrib.auth.models import User
    >>> from django.db import models
    >>> 
    >>> class MyUser(models.Model):
    >>>     class Meta:
    >>>         abstract = True
    >>>         db_table = 'user' # new auth_user table name
    >>>
    >>>     # New field
    >>>     phone = models.CharField('phone number', blank=True, max_length=20)
    >>> 
    >>>     # Email could be null
    >>>     email = models.EmailField(blank=True, null=True)
    >>>
    >>>     # New (stupid) method
    >>>     def get_phone(self):
    >>>         return self.phone
    >>> 
    >>> contribute_to_model(MyUser, User)
    """
    # Contrib should be abstract
    if not contrib._meta.abstract:
        raise ValueError('Your contrib model should be abstract.')

    protected_get_display_method = []
    # Update or create new fields
    for field in contrib._meta.fields:
        try:
            destination._meta.get_field_by_name(field.name)
        except models.FieldDoesNotExist:
            field.contribute_to_class(destination, field.name)
            if field.choices:
                setattr(destination, 'get_%s_display' % field.name, curry(destination._get_FIELD_display, field=field))
                protected_get_display_method.append ('get_%s_display' % field.name)
        else:
            current_field = destination._meta.get_field_by_name(field.name)[0]
            current_field.null = field.null
            current_field.blank = field.blank
            current_field.max_length = field.max_length

    # Change some meta information
    if hasattr(contrib.Meta, 'db_table'):
        destination._meta.db_table = contrib._meta.db_table

    # Add (or replace) properties and methods
    protected_items = dir(models.Model) + ['Meta', '_meta'] + protected_get_display_method #TODO: use a set() ??

    for k, v in contrib.__dict__.items(): #TODO: iteritems() instead ??
        if k not in protected_items:
            setattr(destination, k, v)
Posted in django, python | Leave a comment