Tahapan Hubungan

August 20, 2010

Tahap-Tahap Dalam Hubungan

Twit dr Mbak AlissaWahid tentang tahap perkembangan hubungan. Twit dari beliau telah dilakukan penyesuaian seperlunya.

OK, mari kita belajar ttg perkembangan hubungan antara sepasang manusia yang merupakan hasil penelitian Andrew G. Marshall. Kata Titiek Puspa: jatuh cinta berjuta rasanya. Dunia milik berdua. Menjalani nasib seperti Romeo & Juliet pun kita yakini, tapi awas, rasa jatuh cinta yg melayang-layang itu ternyata cuma bertahan 18-36 bulan. Bahkan belum bisa dibilang loving relationship.

Lirikan mata yg bikin perut mulas, debar hati saat ketemu, masih bisa menghilang ditelan hari, tak berkembang jadi hubungan yang kuat. Saat jatuh cinta, ternyata frekuensi otak melakukan ‘sinkronisasi’ sehingga tiba2 menemukan banyak kesamaan. Misal: “tnyata kita sama2 suka GnR lho”. Saat jatuh cinta, perbedaan-perbedaan yang ada terabaikan karena sinkronisasi itu, makanya berasa ketemu soulmate, pasangan jiwa.. cocook bgt!

Saat jatuh cinta, kelemahan-kelemahan pasangan nggak bermakna. Misal: suka mukul? “cinta kami pasti akan membuatnya berubah..” Apalagi abis berantem. kl fase jatuh cinta, saat baikan ini saat makin dalem jatuhnya cinta.. dunia suejuuk! Nah, pasangan yang bilang “kok sudah tak ada lagi cinta di antara kami?” biasanya yang dimaksud ya rasa jatuh cinta itu.

Nah, setelah melewati fase jatuh cinta, baru masuk hubungan yang sesungguhnya. Ada 6 tahap yang biasanya dilalui pasangan, dengan tantangan yang berbeda-beda. 6 tahap hubungan : blending, nesting, self-affirming, collaborating, adapting, renewing.

Blending biasanya masa hubungan tahun pertama (di tengah fase jatuh cinta, fase blending sudah mulai muncul) sampai akhir tahun kedua hubungan.

Nesting terjadi dalam masa hubungan sampai akhir tahun ketiga. Di sini mulai muncul berantem beneran.

Self-affirming itu tahap hubungan di tahun keempat sampai kelima dimana kebutuhan individu mulai muncul lagi. Mulai ada kompromi.

Collaborating itu tahap hubungan mulai th ke5 sampai 15. Sudah mulai mapan, tapi kadang juga bosan. Besar kemungkinan “jalan sendiri2″.

Adapting ini masa hubungan yang paling rapuh. Penuh dengan tantangan di luar hubungan itu sendiri. Misalnya menghadapi anak remaja. Fase ini terjadi di tahun ke 15-25.

Tahap hubungan terakhir yaitu renewing. Ini yg kita lihat dr orangtua kita yg sudah melewati masa 25 tahun pernikahan: penerimaan total.

12-18bulan sejak saat jatuh cinta, chemistry sang dua sejoli mulai menurun. Perbedaan mulai terasa, menimbulkan kejutan-kejutan. Blending dlm hubungan adalah saat dimana 2 individu mulai menyatukan perbedaan2. Yg suka lagu metal mulai terbiasa dengan lagu2 opera. Kunci di tahun 2-3 dlm tahap nesting adalah mendengarkan, krn akan membantu kita memahami pasangan seutuhnya. Hubungan yang sehat memberi ruang yang seimbang untuk kedua dorongan diri tersebut. Kita belajar mengikhlaskan sebagian untuk mendapatkan keduanya.

Tahun ke2-3 hubungan adalah fase nesting (bersarang). Komitmen makin jelas. Di sini loving attachments mulai terbentuk. Dalam hubungan fase nesting, banyak hal yang sebelumnya ditahan mulai bermunculan. Tadinya cuek pasangan suka telat, sekarang mulai sebel. Di fase nesting, mata yang tadinya hanya tertuju untuk pasangan, sudah mulai bisa menyadari ada orangtua, keluarga, teman dll. Makanya dalam hubungan fase nesting, banyak pasangan mulai sering berantem. Jadi hal terpenting adalah mencari cara tepat untukmengatasi perbedaan.

Next stage: Self-Affirming. Ini saat pasangan mulai kembali ke kebutuhan personal, bukan lagi mendahulukan hubungan dengan pasangan. Tadinya berdua lebih baik, sekarang pengen yang sendiri-sendiri dong. Lebih bebas, nggak perlu jaga perasaan pasangan. Fase Self-Affirming ini di usia hubungan 3-4 tahun. Kadang bikin shock, apalagi kalo di fase-fase sebelumnya semua dilakukan barengan. Fase self-affirming ini saat kita mulai punya kompromi-kompromi utk menjaga keseimbangan individual dengan kebutuhan hubungan. Yang berat di fase Self-Affirming kalo ada 1 pihak yang dependen. Merasa ‘ditinggalkan’ saat pasangan mulai sibuk dengan diri sendiri. Padahal justru independensi di fase SelfAffirming itu jadi fondasi yang kuat utk interdependensi jangka panjang.

Fase Collaborating: usia hubungan 5-15 tahun. Rasa aman sudah ada, masuk bentuk kerjasama karena saling tergantung. Mapan deh. Tantangan: hubungan yang terlalu mapan kadang menimbulkan kebosanan. Nggak ada greng. Kalo komunikasi jelek, sibuk sendiri-sendiri. Fase Collaborating adalah fase terberat dalam perkembangan hubungan perkawinan. Di Inggris, sebagian besar perceraian terjadi di fase ini. Di fase Collaborating ini, yang paling menentukan adalah saling dukung yg besar, bukan saling tuntut. Bisa runyam.

Hubungan terus berkembang masuk ke fase Adapting, tahun 15-25an. Adaptasi bukan dalam hal hubungan, tapi ke hal-hal lain. Anak remaja, karir stuck, dll. Di fase adapting ini, pasangan juga sudah realistis terhadap kebiasaan/kepribadian pasangannya. “Abis gmn, dia emang judes..”. Jadi di tahap hubungan yang ini, yang berat adalah melawan pikiran jahat “dia sih nggak mungkin mau berubah demi saya/anak2..”. Skill yang diperlukan untuk survive di fase Adapting adalah mendengarkan, supaya betul-betul paham harapan pasangan.

Fase terakhir adalah Renewing, setelah usia hubungan melampaui 25 tahun. Jika mampu melewati tahap-tahap sebelumnya dengan baik, ini masa keemasan: damai, penuh cinta. Tantangannya hanya saat2 puber kedua atau menopause yg memang memunculkan hal2 khusus. Tp umumnya hubungan sgt oke. Bila sudah sampai tahap renewing ini, keluarga menjadikan pasangan ini sbg sumber inspirasi & pusat kekuatan

Semoga kita semua bs melampaui keenam tahap hubungan dg baik smp jd kakek nenek & jd teladan anak cucu. Amiin..


Use Excel to compare two lists of data

September 5, 2008
Applies to: Microsoft Office Excel 2003

For financial record-keeping, you often have to compare two lists to
find data that appears on one but not on the other. Which new clients
need to be added to the master database? Which credit card receipts are
not reflected on the monthly statement, and vice versa? What checks and
deposits are still outstanding? It’s a tedious task if you do it
manually.

Microsoft Office Excel 2003 can help you perform this task faster
and more accurately. In many cases, you can do it even if the data is
not provided in a standardized form in both lists.

Comparing two lists of assets

In this article, you’ll use data from the Compare Two Lists sample datasheet to learn how an accountant could use Excel functions to compare two lists of assets — the fixed asset records for a company and a property tax affidavit that must be updated annually. It’s a five-step process:

  1. Make sure each asset has a unique identifier.
  2. Find assets on the property tax affidavit that are not in the fixed asset records.
  3. Find assets in the fixed asset records that are not on the property tax affidavit.
  4. Sort lists to see nonmatching assets more easily.
  5. Review nonmatching assets and check for accuracy.

Step 1: Make sure each asset has a unique identifier

The following illustrations show the two lists that you want to
compare — a list of assets from a property tax affidavit and a list of
fixed asset records.

Business assets on property tax affidavit and on fixed asset records

Property tax affidavit and fixed asset records

As you see, the property tax affidavit does not have unique
identifiers, such as asset numbers, for each asset. But to compare
these lists, assets in each one must have a unique identifier.

In this example, the best way to identify each asset is by a
combination of asset description and date, so you’ll add a new column
called “Description & Date” to each list.

Note In the Compare Asset Lists sample
datasheet, the property tax affidavit and the fixed asset records have
been copied onto one worksheet.

Add a “Description & Date” column to the fixed asset records

  1. In the Fixed Asset Records area of the worksheet, select the Asset column,
    and then on the Insert menu, click Columns.
  2. In cell G2, type Description & Date, and then press ENTER.
  3. Select cell G2.
    On the Format menu, click Cells, click the Alignment tab, select Wrap text, and then click OK.
  4. In cell G3, type =H3&” “&YEAR(I3). This combines the description from cell H3 and the year from cell I3 into one field.
  5. To copy the formula from cell G3 to cell G14, select cell G3 and then drag the fill handle Fill handle to cell G14.
  6. To make the column width fit the results, double-click the boundary to the right of the Description & Date column heading.

Fixed asset records with combined description and date in new column

Fixed asset records with combined description and date

Add a “Description & Date” column to the property tax affidavit

  1. In the Property Tax Affidavit area of the worksheet, select the column to the right of the Cost column, and then on the Insert menu, click Columns.
  2. In cell E2, type Description & Date, and then press ENTER.
  3. Select cell E2.
    On the Format menu, click Cells, click the Alignment tab, select Wrap text, and then click OK.
  4. In cell E3, type =C3&” “&B3.
  5. To copy the formula from cell E3 to cell E12, select cell E3, and then drag the fill handle Fill handle to cell E12.
  6. To make the column width fit the results, double-click the boundary to the right of the Description & Date column heading.

Property tax affidavit with combined description and date in new column

Property tax affidavit with combined description and date

Now that you’re comparing apples to apples, you can get down to business.

Step 2: Find assets on the property tax affidavit that are not in the fixed asset records

  1. In the Property Tax Affidavit worksheet, select the column to the right of the Description & Date column,
    and then on the Insert menu, click Columns.
  2. In cell F2, type Missing?.
  3. In cell F3, type =ISNA(MATCH(E3,$I$3:$I$14,FALSE)).
  4. To copy the formula from cell F3 to cell F12, select cell F3, and then drag the fill handle Fill handle to cell F12.

Assets that are on the property tax affidavit but not in the fixed asset records will display TRUE in the Missing? column.

New
Missing? column showing whether an asset is not found in other list

New Missing? column

Step 3: Find assets in the fixed asset records that are not on the property tax affidavit

  1. In the Fixed Asset Records worksheet, in cell M2, type Missing?.
  2. In cell M3, type =ISNA(MATCH(I3,$E$3:$E$12,FALSE)), and then press ENTER.
  3. To copy the formula from cell M3 to cell M14, Select cell M3, and then drag the fill handle Fill handle to cell M14.

Assets that are in the fixed asset records but not on the property tax affidavit will display TRUE in the Missing? column.

Step 4: Sort lists to see nonmatching assets more easily

To more easily see the assets that are not on both lists, you can sort the lists.

Note If you sort the lists without first
following these steps to convert the formulas to values, the formulas
will not calculate correctly. In a large database, converting the
formulas to values can also help avoid long recalculation times.

Sort for nonmatching assets in the Property Tax Affidavit worksheet

  1. Drag the pointer to select cells A2 to F12.
  2. On the Edit menu, click Copy.
  3. On the Edit menu, click Paste Special.
  4. In the Paste Special dialog box, under Paste, click Values, and then click OK.
  5. On the Data menu, click Sort.
  6. Under My data range has, click Header row; in the Sort by box, click Missing?, and then click OK.

Sort for nonmatching assets in the Fixed Asset Records worksheet

  1. Drag the pointer to select cells H2 to M14.
  2. On the Edit menu, click Copy.
  3. On the Edit menu, click Paste Special.
  4. In the Paste Special dialog box, under Paste, click Values, and then click OK.
  5. On the Data menu, click Sort.
  6. Under My data range has, click Header row; in the Sort by box, click Missing?, and then click OK.

You can now easily see which assets may need to be added or deleted to update the property tax affidavit.

Property tax affidavit and fixed asset records sorted by
Missing? column

Property tax affidavit and fixed asset records sorted by Missing? column

Step 5: Review nonmatching assets and check for accuracy

Before you update the property tax affidavit, it’s a good idea to
manually review the nonmatching assets — which is fortunately a lot
faster than manually comparing the entire list. Review the nonmatching
assets and determine why they don’t match. Were the assets retired or
sold? Are they new assets that should be added, or are they assets that
are not required to be reported on the affidavit? Or did the assets
fail to find a match because of misspellings or other errors?

Other ways to prepare data for matching

Sometimes the data in two lists must be standardized before Excel
can compare the lists. In the preceding example, the dates in one list
were converted to years, and two fields were combined into one. The
following table shows common data inconsistencies and suggested Excel
functions that you can use to prepare data for matching.

Problem Example How to modify
Inconsistent abbreviations Litware, Inc.
vs. Litware, Incorporated
Use the LEFT function to create a field with only the number of characters from the left that you specify.
Extra numbers or characters on one list 12345 vs. 12345-1033 Use the LEFT or RIGHT functions to create a field with only the number of characters from the left or right that you specify.
Imprecise numbers caused by estimates, rounding variances, or sales tax $12,000 vs. $12,011 Use the ROUND function to create a field with comparable amounts.
Extra spaces Jae B. Pak vs. Jae B. Pak Use the TRIM function to remove all spaces from text except single spaces between words.



Install Ubuntu Hardy Heron (8.04.1) on the Acer Aspire One

September 4, 2008

Fully functional:

  • Suspend / Resume
  • Video (with desktop effects)
  • Wireless Networking
  • Wired Networking
  • Webcam
  • USB
  • Silent Fan

Partial Function:

  • Card Readers (only work if card in when booting)
  • Audio – there is sound, issues detailed below

Not Functional:

  • Hibernate on A110L
  • Card Reader power saving
  • wifi power saving
  • wifi kill switch

Prerequisites:

Before you begin you will need the following:

  • A copy of 8.04.1 Hardy Heron.
    This is the latest version. If you downloaded the ISO a while ago, it may be 8.04.0. The original 8.04.0 release will not even boot.

  • An external USB CD-ROM. If not:

Note on using this guide

This guide was written with Ubuntu in mind. Generally everything works the same with the other variants of the distribution (Kubuntu, Xubuntu). For ease of use gedit is the text editor we’ll be using. If you are using a variant please substitute a different text editor (kate for Kubuntu, mousepad for Xubuntu or just use vim/emacs/nano).

Step One: Preparation

(Skip this step if you have an external USB CD-ROM)

If we don’t have any external USB CD-ROM the first thing we need to do is create a bootable copy of the Ubuntu LiveCD on a memory key. This will be our install media for the Aspire One. Its actually pretty similar to creating recovery media for Linpus Lite (the included version of Linux).

Download and copy the LiveUSB .deb file from the link above to a memory key (you can use the same one we we are going to format to create the install media, we only need this file once), and remove the memory key. The LiveUSB software should only be installed when booted off the LiveCD environment, so we do that next.

Boot to the 8.04.1 Live CD on your other computer, and choose the first option off the boot menu (Try Ubuntu). When you reach the desktop insert the memory key with the LiveUSB software one it and double click. Follow the prompts to install it. Now we can create our bootable USB key. Start the LiveUSB application from System -> Administration -> Install LiveUSB. Select the target device (my two keys were listed by a human readable name, so it was easy to find) and click Execute. It will give you a warning about data loss, so double check that you selected the correct device and continue.

Once that is done, you can shut down the other computer and remove the memory key.

Step Two: Install Ubuntu

Shut down your Aspire One and insert the external USB CD-ROM or the memory key that we just used. Turn it on and tap F12 to bring up the boot menu.

With a CD-ROM, choose the USB CD-ROM option. With the bootable memory key created, choose the USB HDD option. This will boot you to the USB CD-ROM/LiveUSB stick, and allow you to install Ubuntu. Install it like normal if you have the hard disk Aspire One. If you have the SDD Aspire One, for good performance and to increase the life of the SSD use a non-journaled filesystem (suggestion: EXT2). If you have already installed with EXT3 then follow this post: http://www.aspireoneuser.com/forum/viewtopic.php?f=5&t=164&st=0&sk=t&sd=a&start=10#p1177 to convert to EXT2. Installation (file copy) will take a LONG time (hour +). If your not currently connected to the internet on a wired connection, you may get an error about setting up a mirror. Don’t worry about it if you do however, its non-fatal.

Step 3: Tweak / Fix

So now we should have an installed Ubuntu system. At this point wire your One into the network. If you use DHCP it should pick up an IP address automatically. The first thing you will want to do is updates, since the wireless driver needs to be reinstalled after every kernel update. Open a terminal (Applications -> Accessories -> Terminal). Do the updates:

sudo apt-get update
sudo apt-get upgrade

WIRELESS:

Now we need to disable the hardware drivers that Ubuntu tries to use before the ones we make will function. So go to System -> Administration -> Hardware Drivers and uncheck everything. It should prompt us to reboot, so lets do it now.

We need to grab the wireless driver, and the things we need to build it, from a terminal:

mkdir source
cd source
wget http://snapshots.madwifi.org/madwifi-hal-0.10.5.6/madwifi-hal-0.10.5.6-r3835-20080801.tar.gz
tar -xzvf madwifi-hal-0.10.5.6-r3835-20080801.tar.gz
cd madwifi-hal-0.10.5.6-r3835-20080801
sudo apt-get install build-essential linux-headers-$(uname -r)

And we build and install:

make
sudo make install
sudo modprobe ath_pci

In order to have the wireless work after reboot, add the following line to /etc/modules (“sudo gedit /etc/modules”) to automatically load the module when booting:

ath_pci

You should now have working wireless. However you may want to do the following to prevent problems (the symbol mismatch) when the module is loaded:

Add ath_hal to the DISABLED_MODULES= stanza in /etc/default/linux-restricted-modules-common

(i.e. ‘DISABLED_MODULES=”ath_hal”‘)

Every time there is a kernel update you will need to perform the following steps to make the wireless work. Go to the directory (madwifi-hal-0.10.5.6-r3835-20080801) and run:

make clean
make
sudo make install

WIRELESS LED:

To get your awesome wireless led to blink for you based on traffic, put these lines in /etc/rc.local, just above the string exit 0 (below doesn’t work).

sysctl -w dev.wifi0.ledpin=3
sysctl -w dev.wifi0.softled=1

The led on the front will now do the association blink, as well as blink based on wireless traffic.

The wifi kill switch uses these keycodes (also to use in rc.local):

/usr/bin/setkeycodes e055 159
/usr/bin/setkeycodes e056 158

CARD READER:

According to DebianAcerOne the following command enables the card reader:

setpci -d 197b:2381 AE=47

The card reader works fine if cards are inserted before booting.

  • it might help to suspend/resume
  • a static entry for the device /dev/mmcblk01p in /etc/fstab might help
  • powersaving can be done with the jmb38x_d3e.sh script

USB MOUNT:

(Do this step only if you get an error inserting a USB stick)

If you insert a memory key, you may notice an error and that it cannot be mounted. This is due to the CD-ROM entry in the fstab. Since we don’t have an optical drive on the One we will comment that out. From a terminal again:

sudo gedit /etc/fstab

You should see a line that looks like:

/dev/sdb        /media/cdrom0   udf,iso9660 user,noauto,exec 0       0

add a hash in front:

#/dev/sdb        /media/cdrom0   udf,iso9660 user,noauto,exec 0       0

Reboot, and automount should work.

NOISE (FAN CONTROL)

Bios v0.3114 doesn’t manage correctly Fan speed, resulting in a very noisy AA0. Solution:

 chmod a+x acerfand
 sudo cp acer_ec.pl acerfand /usr/local/bin/
  • To run it straight away:

 sudo acerfand
  • To run it at boot:

 sudo gedit /etc/rc.local

Insert the following line above the exit 0 at the bottom:

 /usr/local/bin/acerfand

The fan is not completely disabled. When the default temperature is reached (60ºC), fan works again. According to Intel, the Atom chip could work until 99ºC.

Optional: Above instructions will work fine, but if you want to define another temperature:

  • Create an /etc/acerfand.conf file. The file is just a shell script that sets up to three values. eg:

INTERVAL=5
FANOFF=60
FANAUTO=70

Those are the default values, if the /etc/acerfand.conf file isn’t found.

INTERVAL is the polling interval in seconds

FANOFF is the temperature (in Celsius Degrees) at or below which to turn the fan off, if it’s currently on auto

FANAUTO is the temperature (in Celsius Degrees) at or above which to turn the fan to auto, if it’s currently off

More information from the original source, AspireOne Wiki.

OPTIMIZING SSD PERFORMANCE:

(Skip this step if you have the hard disk Acer Aspire One)

The performance of the SSD drive can be significantly improved by a few tweaks described in an article by Jason Perlow (Tweek #1 is not working with Ubuntu on the Aspire One). The most important of these are described here.

Change the file system mount options on SSDs to “noatime”

Edit /etc/fstab (sudo gedit /etc/fstab) and change the the option “relatime” to “noatime”. The line for the root partition should then be something like:

UUID=f0ae2c59-83d2-42e7-81c4-2e870b6b255d / ext2 noatime,errors=remount-ro 0 1

Use the “noop” I/O scheduler

Edit /boot/grub/menu.lst using your favorite editor, and add “elevator=noop” as an option. The default kernel configuration, found in the last part of the file should be something like:

title           Ubuntu 8.04.1, kernel 2.6.24-19-generic
root            (hd0,0)
kernel          /boot/vmlinuz-2.6.24-19-generic root=UUID=f0ae2c59-83d2-42e7-81c4-2e870b6b255d ro quiet splash elevator=noop
initrd          /boot/initrd.img-2.6.24-19-generic
quiet

In order for the changes to remain when updating the kernel, also in menu.lst, find the line

# defoptions=quiet splash

and add “elevator=noop” as an option:

# defoptions=elevator=noop quiet splash

REDUCING SSD WEAR:

(Skip this step if you have the hard disk Acer Aspire One)

Frequent writes to the SSD will cause failure eventually. We can reduce the number of writes to the SSD my moving our logs to a temporary filesystem in RAM that gets destroyed at ever reboot. Now this means your logs will not be persistent across reboots making debugging difficult in some cases. This step is optional of course, so if you need the logs for an extended period of time do not follow these steps.

Open your fstab again, and add the following lines:

sudo gedit /etc/fstab
tmpfs      /var/log/apt    tmpfs        defaults           0    0
tmpfs      /var/log        tmpfs        defaults           0    0
tmpfs      /tmp            tmpfs        defaults           0    0
tmpfs      /var/tmp        tmpfs        defaults           0    0

AUDIO:

Out of the box there are various issues with the sound. These range from headphone detection not functioning correctly, to the internal MIC not working. There are solutions to these problems. Currently, however, there is no known way to get everything working at once. All of the steps begin the same way, rebuilding ALSA:

sudo apt-get install module-assistant
sudo m-a update
sudo m-a prepare
sudo m-a a-i alsa
sudo alsa force-unload
sudo depmod -ae
sudo modprobe snd-hda-intel

Add the following line to the end of /etc/modules in order to ensure that the module is loaded during bootup:

snd-hda-intel

Now we need to make a choice. To have the internal MIC non-functional (external works), but sound working after suspend and resume, we edit /etc/modprobe.d/alsa-base (sudo gedit /etc/modprobe.d/alsa-base) and add the following line to the bottom:

options snd-hda-intel model=toshiba

Reboot for that to take effect.

To have the internal MIC function correctly, but no sound after suspending and resuming the computer add or change the following to the /etc/modprobe.d/alsa-base as before:

options snd-hda-intel model=auto

Again, reboot for this to take effect.

For some unknown reason some people don’t hear any sound with either option. If you experience this problem you might want to use the option in /etc/modprobe.d/alsa-base as before to the following to resolve this problem:

options snd-hda-intel model=acer

If you experience crackling sound after rebooting, insert the following line in /etc/modprobe.d/blacklist:

blacklist snd_pcsp

Optional: The default sound level is low. Open a terminal and type alsamixer to adjust volume.

TWEAKS TO MAKE BETTER USE OF THE ASPIRE ONE’S SMALL SCREEN:

There are various methods that will help you make better use of the Aspire One’s small screen. One of the most important is being able to move windows that are too large to fit on the screen at once. To move a hidden part of the window into view, click and drag with the left mouse button on any part of the window while holding down the ALT key. However, you won’t be able to drag windows so the top of the window is above the top of the screen. To fix that, enter the following in a terminal window:

gconftool-2 --set /apps/compiz/plugins/move/allscreens/options/constrain_y --type bool 0

Since the Aspire One’s screen has almost twice as much resolution horizontally as vertically, having panels on both the top and bottom is not ideal. You may want to remove the top or bottom panels, make them smaller, or move them so that they are vertical, on the left and right side, instead of horizontal on top and bottom.

HIBERNATE:

In some set-ups, using hibernate has been reported to cause file corruption.

TWEAKS FOR POWERSAVING (Optional):

Add the following to the /etc/rc.local file:

# Economize the SSD
sysctl -w vm.swappiness=1               # Strongly discourage swapping
sysctl -w vm.vfs_cache_pressure=50      # Don't shrink the inode cache aggressively

# As in the rc.last.ctrl of Linpus
echo ondemand > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo ondemand > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate_max > /sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate

echo 3000 > /proc/sys/vm/dirty_writeback_centisecs
echo 20 > /proc/sys/vm/dirty_ratio
echo 10 > /proc/sys/vm/dirty_background_ratio

echo 1 > /sys/devices/system/cpu/sched_smt_power_savings
echo 10 > /sys/module/snd_hda_intel/parameters/power_save
echo 5 > /proc/sys/vm/laptop_mode

#Decrease power usage of USB while idle
[ -L /sys/bus/usb/devices/1-5/power/level ] && echo auto > /sys/bus/usb/devices/1-5/power/level
[ -L /sys/bus/usb/devices/5-5/power/level ] && echo auto > /sys/bus/usb/devices/5-5/power/level

NETBOOK REMIX (Optional):

To install Ubuntu Netbook remix -

  • Insert the following into /etc/apt/sources.list:

deb http://ppa.launchpad.net/netbook-remix-team/ubuntu hardy main
deb-src http://ppa.launchpad.net/netbook-remix-team/ubuntu hardy main
  • then execute

sudo apt-get update
sudo apt-get install go-home-applet human-netbook-theme maximus ume-launcher window-picker-applet
  • Add maximus as startup program (system > preferences > sessions > startup programs)

  • Change the desktop theme to Human-Netbook (system > preferences > appearance > theme)

  • Delete the bottom panel
  • Reconfigure the top panel to contain the following items -
    • Go Home Applet
    • Window Picker Applet
    • Notification Area
    • Mixer Applet
    • Clock
  • There is a bug in the ume-launcher after resuming from suspend. To work around this place the following in /etc/pm/sleep.d/01UMELauncher -

#
# Copyright 2008 Matteo Collina <matteo.collina@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.

export DISPLAY=:0.0

TMPFILE=/tmp/.launcher/resume-event

case "$1" in
        suspend|hibernate)
                rm -rf $TMPFILE
                echo "Removed resume-notify file"
        ;;
        resume|thaw)
                touch $TMPFILE
                echo "Created resume-notify file"
        ;;
esac

exit $?
  • Make the above file executable -

sudo chmod +x /etc/pm/sleep.d/01UMELauncher

Flash 9.0.48 (Optional, recommended for 512M of RAM):

Ubuntu Hardy installs flash version 9.0.115, this version needs a lot of memory to work and makes ‘AspireOne’ slower than it is. A good option is to come back to the last fast official version of flash (9.0.48). Just download ‘Flash player 9 (99MB)’ file from:

http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_14266&sliceId=2

In this file there are a lot of old flash versions, navigate to 9r48 and uncompress this folder. Double click ‘flash-player installer’, choose ‘Run in terminal’ and follow the instructions.


Runtime form controls

August 20, 2008

Creating runtime form controls can be useful in a variety of circumstances. Any type of control can be added at runtime: groups, string edits, buttons etc.

Standard Axapta uses this technique to dynamically add ‘Action’
buttons to forms when required. The code to add controls for these
functions is called from the new() method of SysSetupFormRun.

Introduction

The basic process to add controls and intercept their events at runtime is as follows:

  • use form.addControl(ControlType, ControlName) to add the control
  • call form.controlMethodOverload(true) to enable over-riding of the control events
  • write appropriate event handler methods on the form

If you are dealing only with buttons, then it is possible to set
the MenuItemType and MenuItemName on the button when it is created. In
this way, you can directly call a report, class or another form, and
you don’t need to write additional code on the form to deal with the
button click.


The Basics

The simplest example uses the init() method of a form to add the
controls, and design-time methods to intercept the control events. Take
note of the control names used during the .addControl() call. In the
example below, the control names are ‘DynamicStringControl’ and
‘DynamicButtonControl’.

/* GeSHi (c) Nigel McNie 2004 (http://qbnz.com/highlighter) */
.code .imp {font-weight: bold; color: red;}
.code .kw1 {color: #0000ff;}
.code .co1 {color: #007F00;}
.code .coMULTI {color: #007F00;}
.code .es0 {color: #666666; font-weight: bold;}
.code .br1 {color: #0000ff;}
.code .br2 {color: #0000ff;}
.code .st0 {color: #FF0000;}
.code .nu0 {color: #000000;}
.code .me1 {color: #000000;}
.code .me2 {color: #000000;}

public void init() {     FormStringControl   formStringControl;     FormButtonControl   formButtonControl;     FormGroupControl    formGroupControl;     ;

     // Adding a group     formGroupControl = this.form().addControl(FormControlType::Group, "MyGroup");     formGroupControl.caption("It's my group!");

     // Adding a string to a group     formStringControl = formGroupControl.addControl(FormControlType::String, "DynamicStringControl");     formStringControl.label("Dynamic string control");

     // Adding another string to the group using the same name.  This will use the same event method as the     // first "DynamicStringControl"     formStringControl = formGroupControl.addControl(FormControlType::String, "DynamicStringControl");     formStringControl.label("Dynamic string control2");

     formButtonControl = this.form().addControl(FormControlType::Button, "DynamicButtonControl");     formButtonControl.text("Dynamic button");

     this.controlMethodOverload(true);

     super(); }

You can then write event handler methods for the controls at the top (element) level of your form.

/* GeSHi (c) Nigel McNie 2004 (http://qbnz.com/highlighter) */
.code .imp {font-weight: bold; color: red;}
.code .kw1 {color: #0000ff;}
.code .co1 {color: #007F00;}
.code .coMULTI {color: #007F00;}
.code .es0 {color: #666666; font-weight: bold;}
.code .br1 {color: #0000ff;}
.code .br2 {color: #0000ff;}
.code .st0 {color: #FF0000;}
.code .nu0 {color: #000000;}
.code .me1 {color: #000000;}
.code .me2 {color: #000000;}

void dynamicButtonControl_Clicked() {     ;

     info ("Dynamic button clicked!"); }

 boolean dynamicStringControl_Modified() {     FormStringControl control = element.controlCallingMethod();     ;

     info (strFmt("Modified dynamic control %1 to %2", int2str(control.id()), control.text()));     return true; }

Note that the first part of the handler method names (before the underscore) exactly matches the control names used in init().


[edit] Adding menu-item buttons

It is usually preferable to keep the amount of code on a form to a
minimum. By setting your dynamically-created buttons to call
menu-items, you can avoid writing the event handlers completely.

The following example adds a menu-item button to a form, which
will open the SalesTable form using the standard Axapta menu-item. Note
that we now must use a FormFunctionButtonControl, rather than a
FormButtonControl.

The button will correctly show the label from the menu-item.

/* GeSHi (c) Nigel McNie 2004 (http://qbnz.com/highlighter) */
.code .imp {font-weight: bold; color: red;}
.code .kw1 {color: #0000ff;}
.code .co1 {color: #007F00;}
.code .coMULTI {color: #007F00;}
.code .es0 {color: #666666; font-weight: bold;}
.code .br1 {color: #0000ff;}
.code .br2 {color: #0000ff;}
.code .st0 {color: #FF0000;}
.code .nu0 {color: #000000;}
.code .me1 {color: #000000;}
.code .me2 {color: #000000;}

public void init() {     FormFunctionButtonControl   formFunctionButtonControl;     ;

     formFunctionButtonControl = this.form().addControl(FormControlType::MenuFunctionButton, "SalesTableButton");     formFunctionButtonControl.menuItemType(MenuItemType::Display);     formFunctionButtonControl.menuItemName(MenuItemDisplayStr(SalesTable));

     super(); }

The same principle can be used to call your own ‘display’, ‘output’
or ‘action’ menu-item. This is useful if the button should perform some
intensive database processing, which would benefit from being
encapsulated in a server-side class.

See the create() method on the KMActionMenuButtonAuto class for a further, more complex example.

See this project for two forms demonstrating the above concepts.


[edit] Adding grid control

In most cases you’d better use visible property of this control’s
type. But sometimes you have to add a grid on an existing form and
without any opportunity of change. This example will help you. Rather
you are making this modification on forms, that are managed from class.
In our tutorial case this is runable tutorial_AddRunTimeControls class.
This following code adds a grid control of the selected table. You may
find similar functionality in the form SysTableBrowser:

/* GeSHi (c) Nigel McNie 2004 (http://qbnz.com/highlighter) */
.code .imp {font-weight: bold; color: red;}
.code .kw1 {color: #0000ff;}
.code .co1 {color: #007F00;}
.code .coMULTI {color: #007F00;}
.code .es0 {color: #666666; font-weight: bold;}
.code .br1 {color: #0000ff;}
.code .br2 {color: #0000ff;}
.code .st0 {color: #FF0000;}
.code .nu0 {color: #000000;}
.code .me1 {color: #000000;}
.code .me2 {color: #000000;}

void addRunTimeControls(FormRun _formRun){     FormGridControl        formGrigControl;     Form                   _form;     FormBuildDataSource    formBuildDataSource;     FormBuildDesign        formBuildDesign;     FormBuildStringControl formBuildStringControl;     FormBuildGridControl   formBuildGridControl;     Object                 formBuildControl;     FormBuildGroupControl  formGroupControl;     CustTable              custTable;     DictTable              dictTable;     TableId                tableID;     ;

    // Adding a Grid  control, this used in  SysTableBrowser    tableID    = picktable();    dictTable   = new DictTable(tableID);    _form = _formRun.form();    formBuildDataSource = _form.dataSource(2);    formBuildDataSource.name(dictTable.name());    formBuildDataSource.table(dictTable.id());    formBuildDataSource.autoQuery(true);    formBuildDesign = _form.design();    formBuildDesign.widthMode(-1);    formBuildDesign.widthValue(600);    formBuildDesign.heightMode(-1);    formBuildDesign.heightValue(400);

    formGroupControl = formBuildDesign.addControl(FormControlType::Group, 'SecondGrid');    formGroupControl.caption("Dynamic Grid");    formGroupControl.widthMode(1);    formGroupControl.heightMode(1);    formBuildGridControl = formGroupControl.addControl(FormControlType::GRID,'Grid');    formBuildGridControl.dataSource(dictTable.name());    formBuildGridControl.name('AddRunTime');

    formBuildGridControl.widthMode(1);    formBuildGridControl.heightMode(1);    this.showFields(tableNum(custTable), formBuildGridControl, formBuildDataSource);

    _formRun.controlMethodOverload(true);    _formRun.init();    _formRun.run();    _formRun.detach();}

And define the fields on grid.

/* GeSHi (c) Nigel McNie 2004 (http://qbnz.com/highlighter) */
.code .imp {font-weight: bold; color: red;}
.code .kw1 {color: #0000ff;}
.code .co1 {color: #007F00;}
.code .coMULTI {color: #007F00;}
.code .es0 {color: #666666; font-weight: bold;}
.code .br1 {color: #0000ff;}
.code .br2 {color: #0000ff;}
.code .st0 {color: #FF0000;}
.code .nu0 {color: #000000;}
.code .me1 {color: #000000;}
.code .me2 {color: #000000;}

public void showFields(tableId                 tableId,                       FormBuildGridControl    formBuildGridControl,                       FormBuildDataSource     formBuildDataSource)

{    FormBuildStringControl          formBuildStringControl;    DictTable                       dictTable;    fieldId                         fieldId;    int                             i;    int                             fieldCnt;    ;    dictTable   = new DictTable(tableId);    for (i=1; i<=3; i++)    {        fieldId = dictTable.fieldCnt2Id(i);        formBuildGridControl.addDataField(formBuildDataSource.id(), fieldId2Ext(fieldId, 1));    }}

See this project for this example.


[edit] Removing the control

To remove a control again, use the following code:

/* GeSHi (c) Nigel McNie 2004 (http://qbnz.com/highlighter) */
.code .imp {font-weight: bold; color: red;}
.code .kw1 {color: #0000ff;}
.code .co1 {color: #007F00;}
.code .coMULTI {color: #007F00;}
.code .es0 {color: #666666; font-weight: bold;}
.code .br1 {color: #0000ff;}
.code .br2 {color: #0000ff;}
.code .st0 {color: #FF0000;}
.code .nu0 {color: #000000;}
.code .me1 {color: #000000;}
.code .me2 {color: #000000;}

element.design().removeControl(elementId)

This also can be usefull to see how a dialog field properties can be changed on the fly
PriceListCopy


Infolog stack trace

August 20, 2008

download (7K) | This is an extension allowing to see stacktrace for each infolog item.

Installation

  • import Dev_StackTrace.xpo
  • recompile
  • add the following code to the \Classes\Info\add:

// RPT DevTools bmi 060915 --->    if(hasSecuritykeyAccess(securityKeyNum(AdminMisc), AccessType::Edit))    {        _sysInfoAction = new SysInfoAction_StackTrace(_txt, xSession::xppCallStack(), _sysInfoAction);    }// RPT DevTools bmi 060915 <--- 
  • compile the info class

Usage

When infolog record is outputed this extension adds an action to it
named “Stack trace” (it is only for users with admin rights). Just
press the button and see stack trace.

If the record has an action already, you can see stacktrace by holding Ctrl button while clicking on the action button.


Image Class

August 20, 2008

Image is a system class for handling image data.

The class can construct and manipulate Image objects of the following file types:

  • Raster (bitmap) formats – .bmp, .gif, .jpg, .png, .tiff, and .exif
  • Vector formats – .emf and .wmf

Because of security reasons the class in Dynamics Ax can not be run from the server and is bound to the client.

The image object can be created from scratch, captured from the screen
or loaded from a file. It can then be cropped, resized, flipped,
rotated etc…

Load an image from file and place it in a table:

Image      image;str        fileName;;

filename = myImagePath + myImageFile;

if (Image::canLoad(Filename))
{
   image.loadImage(Filename);
   myTable.imageContainer = image.getData();
}

…and to display the image on a form:

Image   Image;container imageContainer;;

imageContainer = myTable.imageContainer;

Image = new Image();
Image.setData(imageContainer);

imageWindow.image(Image);
imageWindow.widthValue(image.width());
imageWindow.heightValue(image.height());

Specifying empty date values

August 19, 2008

If you want to set a date field to an empty date or need to compare if a date field is empty, you can use the datenull() function. It is a method of the Global class and will simply return 011\1900.

This leads to more things:

  1. You can write dates in Axapta X++ editor using backslashes, e.g. 144\2006
  2. An empty date in Axapta is specified as January 1st, 1900.
  3. You
    can use methods from the Global class without having to write
    “Global::”. So, you can write “if date == datenull()” and you do not
    have to write “if date == Global::datenull()”. This works with all the
    methods from the Global class.

Using global search for virtual tables

August 19, 2008

The global search is a feature in Dynamics Ax 4.0 which allows you to
search for a string in several tables (like a full text search). You
setup some tables and fields to be searched in and start a data crawler
that collects the data to be searched.

Now, if some of your
tables that are searched belong to a virtual company, the data crawler
will mark them as records of the company it is running in. That means
that if you want to search for your virtual data from a different
company, it will return no results.

Example: you have the
companies xxx and yyy and a virtual company vir. Table CustTable is
virtual (dataareaid of the records is vir). The data crawler runs in
company xxx and will mark the CustTable records as belonging to company
xxx .
Now, if you start a search in company yyy, it will not find
the Custtable records as they seem to belong to a different company.
You could only set up a second data crwaler for company yyy which would
collect exactly the same records and you would need to store them twice
in your database.

The following changes will circumvent that:
you will be able to see data from different companies. There are some
drawbacks, however: you will be able to see search results from your
“data crawler company”. But it the data is from a non-virtual table,
you will not be able to see the results. But I hope it will lead you to
a way where you can make your own modifications to get the best out of
the global search. Remember: all changes you make are at your own risk.

Here are the changes you have to do:

Class SysGSSearchStart, method startSearch
comment the following line:

infolog.add(Exception::Warning,”@SYS98793″);

With that, there will be no warning if you are working in a company where the data crawler is not running.

Class SysSearch, method search:

at line 28, just after “if (!searchname)” add:

select firstonly RecId from sysSearchName
where sysSearchName.Design == ‘SDS_xxx_default’
&& sysSearchName.LanguageId == this.languageId();

if (!sysSearchName)

replace the xxx in the ‘SDS_xxx_default’ with the company id where the data crawler is running.

Class SysSearch, methods searchWord and searchExactWord:

at line 11, replace the “where sysSearchName.Design == this.design() &&” with:

where (sysSearchName.Design == this.design()
sysSearchName.Design == ‘SDS_xxx_default’) &&

again, replace the xxx in the ‘SDS_xxx_default’ with the company id where the data crawler is running.

Class SysSearchDoDataSearch, method buildItemListXML:

at line 11, after a while select indextable from sysDataSearch block, add the following code:

changecompany(‘xxx’)
{
sysDataSearch = null;
while select IndexTable from sysDataSearch
{
dictTable = new DictTable(sysDataSearch.IndexTable);
if (dictTable.rights() != AccessType::NoAccess)
searchTableMap.insert(dictTable.id(),0);
}
}
sysDataSearch = null;

Replace ‘xxx’ with the company id where the data crawler is running.

At line 77, after select sysDataSearch where sysDataSearch.SearchGroupId == m_eSearchGroupDef && sysDataSearch.IndexTable == tableid; add the following code:

if (!sysDataSearch)
{
changecompany(‘xxx’)
{
sysDataSearch = null;
select sysDataSearch
where sysDataSearch.SearchGroupId == SearchGroupDef
&& sysDataSearch.IndexTable == tableid;
}
}

Replace ‘xxx’ with the company id where the data crawler is running.


Using the Windows API from within Axapta

August 19, 2008

It seems that calling Windows API functions from Axapta is viewed as some
sort of mysterious magic by most Axapta developers. Unfortunately,
there are times when you need to do something that requires tight
integration with functionality that exists outside of the system. While
there are other methods of interfacing between bits of code, including
COM, XML-RPC, or even .NET, using the Windows API can sometimes be very
efficient, and powerful.

For beginner WinAPI coders who are also Axapta programmers, with at least some programming experience in C or C++,
I felt it might be better to answer a question from my colleagues about
calling WinAPI calls from Axapta, outside of those already wrapped by
the WinAPI:: or WinGDI:: classes.

Axapta
provides basic functionality to open a handle to a library (DLL file),
and a handle to a function within that library. The functionality is
handled within two classes, DLL:: and DLLFunction:: respectively, and allows you to call practically any piece of code within any dynamic link library.

The most common use for this is naturally to make calls into the
Windows API, but there’s no reason why you can’t provide your own
functions within a DLL and call them from Axapta, but be aware that the
DLL file must be installed on either the client or server, depending on
where the code will execute.

The DLL:: class opens a DLL file and acts as a handle for DLLFunction::
to use when defining handles for calls. If the DLL isn’t already opened
by Axapta internally (as would be the case with the standard Windows
API DLL files), it will also silently handle the opening,
initialisation, and closure of the DLL in conjunction with the garbage
collector.

The DLLFunction:: class defines a handle to a function’s
symbol within the DLL, and defines the return value and the parameters
of the function. This is important to define correctly, as defined by
the C/C++ headers; otherwise you will head straight into problems with
Axapta crashing, either during the call, or later on. Don’t worry, this
is easily determined, and I’ll explain how this works. If you don’t
have the header files (*.h) with a windows compiler, you can look at Google Code Search.

Before going into detail with how this works, you might need to know
what’s going on behind the scenes, especially how functions call other
functions from the computer’s perspective. Since that’s not really in
scope here, I’ll very quickly describe only the elements of this you
need to know to make your calls work from Axapta. If you already know
this, you can skip past it.

When you call a function, its parameters get pushed onto the stack, which is a FILO
data model. The function being called then takes these items off the
stack and can use them as variables. The calling function knows
precisely how many items it needs to put onto the stack, and the
function itself knows how many items it needs to take off the stack.

As you know, once a called function has done its work, it can return a value. The process works the same way in reverse, pushing the return value onto the stack for the caller to pop from the stack.

Sometimes an example helps, so let’s consider the following simplistic example in C:

int foo(int bar, char* baz)
{
printf(“Qux: %s”, baz);

return (bar * 2);
}

void quux(void)
{
int corge = foo(10, “Grault”);
}

Consider when the quux() function calls foo(), it will push the value 10 and a pointer to the null-terminated string “Grault” onto the stack, and jump to the location in memory where the code for foo() exists. Subsequently, foo() will pop these two values from the stack to be able to use them. When foo() returns, it will push the value of 20 onto the stack, and quux() will pop that from the stack and use it as the value for corge.

Of course, there’s a lot more going on in the stack, in fact there are a few stacks, but we don’t need to cover that here.

To be able to call your function, you will need to know which DLL
your function is in, and the real name of the function as exported by
the DLL’s symbols. I mention this because it seems obvious, but you
should remember that Microsoft generally provide two versions of
functions if they use strings, for ANSI and wide-characters, normally
with an “A” or “W” suffix respectively. The headers
for these functions often hide this fact, as does MSDN. Opt for the
ANSI version – Axapta will convert strings based on the locale.

To cover the subject quickly, let’s build a small example form that
uses the Windows API to draw the appropriate icon for a specified file
within a window pane.

Build a form with a Window control. In this example, I have named the window Icon. The window control needs have the width and height both set to 32 pixels (icon size), and the AutoDeclaration property enabled.

The form needs some code. Add some variables we will need to the class declaration of the form:

public class FormRun extends ObjectRun
{
// DLL file handles
DLL shellDLL; // shell32.dll
DLL userDLL; // user32.dll

// Function call handles
DLLFunction extractAssociatedIconFunc;
DLLFunction destroyIconFunc;
DLLFunction drawIconFunc;

// Our icon handle, taken from windows
int hIcon;

// These are from the windows headers, used later in the code!
#define.DI_MASK(0×01)
#define.DI_IMAGE(0×02)
#define.DI_COMPAT(0×04)
}

We need to initialise many of these variables first. Using the init()
function on the form, we can initialise the DLL handles, and the
functions. The DLL handles only need the name of the DLL file,
obviously, but the DLL function handles need to be configured with the
primitive types that will be appearing on the stack. Even parameters or
the return value are not used, you must specify them, or the stack will
be out of synchronisation.

To help you define your primitive types, Axapta has a kernel enumerator called ExtTypes,
which contains all the basic types you will need. You need to then take
what’s listed in the header file and determine what primitive type it
is. For example, windows defines many functions which return a value of
BOOL, however this is simply a type definition in C for an
integer. It’s your responsibility to match these values up logically by
working through the definitions. Don’t worry; I’ve done the hard work
for you in this example!

Override your form’s init() function with the following code:

public void init()
{
;

// Initialise the form first
super();

// Set up our call for ExtractAssociatedIcon()
extractAssociatedIconFunc =
new DLLFunction(shellDLL, “ExtractAssociatedIconA”);
extractAssociatedIconFunc.returns(ExtTypes::DWord); // HICON
extractAssociatedIconFunc.arg(ExtTypes::DWord, // HINSTANCE hInst
ExtTypes::String, // LPTSTR lpIconPath
ExtTypes::Pointer); // LPWORD lpiIcon

// We also need a function to destroy the icon handle once we’ve used it
destroyIconFunc = new DLLFunction(userDLL, “DestroyIcon”);
destroyIconFunc.returns(ExtTypes::DWord); // BOOL
destroyIconFunc.arg(ExtTypes::DWord); // HICON hIcon

// This is our call for drawing the icon onto a window
drawIconFunc = new DLLFunction(userDLL, “DrawIconEx”);
drawIconFunc.returns(ExtTypes::DWord); // BOOL
drawIconFunc.arg(ExtTypes::DWord, // HDC hDC
ExtTypes::DWord, // int xLeft
ExtTypes::DWord, // int yTop
ExtTypes::DWord, // HICON hIcon
ExtTypes::DWord, // int cxWidth
ExtTypes::DWord, // int cyWidth
ExtTypes::DWord, // uint istepIfAniCur
ExtTypes::DWord, // HBRUSH hbrFlickerFreeDraw
ExtTypes::DWord); // UINT diFlags
}

When the form runs, we want the icon to be updated with an icon from a file. To do this, we will override the run method on the form. After the form has started normally, we will make a call to ExtractAssociatedIcon() to find our hIcon (icon handle) value. We’ll save this value for later use. Once this is done, we’ll need to draw the icon for the first time.

Axapta provides one additional bit of help here for complex
structures containing primitive types, or any other place where you
need to pass a pointer on the stack. The kernel class Binary::
lets you allocate memory in the system, and have it freed by the normal
Axapta garbage collection routines. This of this as your answer to malloc(), and also your answer to creating and reading C-style structures.

Override your form’s run() method with the following, and feel free to change the file to any file on your system:

public void run()
{
Binary binary;
;

// Run the form normally
super();

/* We need to build a binary item for two bytes (a short), since windows
* has an “in/out” pointer for the icon information.
*/

binary = new Binary(2); // 2 bytes = short

// Call the ExtractAssociatedIcon() function
hIcon = extractAssociatedIconFunc.call(NULL,
“C:\\WINDOWS\\EXPLORER.EXE”,
binary);

// Make sure we got an icon (we should, if the file exists)
if (!hIcon) {
throw error(“Unable to get hIcon”);
}

// Do the initial drawing of the icon
this.drawIcon();
}

Since the Windows API will allocate stuff on its side, we need to
clean up some memory when the form is closed. To do this, we call DestroyIcon() with the icon’s handle. Override your form’s close() method with the following snippet:

public void close()
{
;

// If we have an icon handle, we need to clean up
if (hIcon) {
destroyIconFunc.call(hIcon);
}

// Close the form
super();
}

Now the fun part: We need to grab the device context of the window,
and use it to draw the icon on to the form. We will use the function DrawIconEx().
Note that we need to lock the device context of the window before
passing it outside for the library to chew on. Add the following method
to your form:

public void drawIcon()
{
;

// Lock the device context of the window so we can use it
Icon.lockDC();

// Paint the icon (we’ll use the window size to determine the icon size)
drawIconFunc.call(Icon.hDC(), 0, 0, hIcon,
Icon.widthValue(),
Icon.heightValue(),
0, NULL,
(#DI_IMAGE | #DI_MASK | #DI_COMPAT));

// Unlock the device context of the window
Icon.unlockDC();
}

Finally, you will also need to override the function paint()
on the Window control. The following code will be called by Axapta
whenever Windows asks Axapta to paint the window. This allows you to
redraw the icon when the form is covered or uncovered by another window
in the foreground, for example. Without this, your icon will disappear
if anything other than the mouse moves over it! Add this code to the Icon control:

public int paint()
{
int ret;
;

// Paint the window first
ret = super();

// Draw the icon
element.drawIcon();

return ret;
}


Color-code your Dynamics environments

August 15, 2008

Since implementing Axapta / Dynamics AX in 2003, we’ve found it invaluable to provide an environment for testing and training as well as our live system (or production environment) to end users. This lets people try different processes or train new employees without fear of screwing up the “real” data.

Occasionally, though, we’ve run into a problem where someone thought they were using the live system, but were actually in the test environment. It’s an easy mistake to make. There is no obvious visual cue to alert a user that they are working on a test system.

There is a way change the color of the Dynamics forms to help indicate what environment is in use. It involved overriding the SysSetupFormRun.run() method, which will be called every time a form is opened. On the class SysSetupFormRun, create a new method with this code:

public void run()
{
SysSQLSystemInfo systemInfo = SysSQLSystemInfo::construct();
;

super();

// Set the color scheme of this instance of the SysFormRun to RGB
this.design().colorScheme(FormColorScheme::RGB);

// If the database name is not the live version, change the color of the form

if (systemInfo.getloginDatabase() != ‘MyDBName’)
this.design().backgroundColor(0×112255);
}

That’s all there is to it. If your live and test systems use the same database name, but the AOS is running on different servers you can modify this code to to match on systemInfo.getLoginServer() != ‘MyServerName’. You can change the color by setting the hex value. It uses the RGB values in reverse order: 0xBBGGRR.

Variations of this code could switch form colors to indicate the current user account, application layer, or company. Less practical uses could match color to the time of day or season of the year. If you find this code useful, leave me a message noting what you did with it.


Follow

Get every new post delivered to your Inbox.