Pages

May 28, 2009

Path Validator

An English translation is available for this post...
הבטחתי, לא?
אז הנה איזה משהו קטנטן (באמת) שהוא חלק מאיזה פרוייקטון שאני עובד עליו. מדובר בואלידאטור שנועד לבדוק "תקינות" של path שמשתמש בכניס. השימושים די ברורים, למעשה כל אפליקציה שדורשת מהמשתמש להכניס Path כחלק מהפעולות שהוא רוצה לבצע.
הואלידאטור הנוכחי בודק אם בכלל יש קלט ואז, אם יש, הוא פשוט בודק אם הנתיב הזה קיים לוקאלית. זה הכל.
יש שם איזה try…catch קטן בכדי לא לפול על wrong arguments exception שיכול לעוף ברגע ש... יש ארגומנטים שלא יכולים להוות נתיב. זה הכל בתכלס. למטה אתם יכולים למצוא את הקוד של הולידאטור ואת השימוש בו. שימו לב שהאיתחול והשימוש בולידאטור נעשה ב-AS, למרות שהוא יכול להיעשות גם בדרך הקונבנציונאלית ב-MXML.
לכל שאלה, טענה וכיו"ב, אתם יודעים איפה למצוא אותי.
תבלו, וחג גבינות שמח!


I promised, didn’t I?
So here is something real tiny that is a part of some project I’m working on. It’s a Validator which checks a file path that the user have entered. The usage is pretty straight forward, any application that requires the user to enter a valid path as part of the operation he wants to perform. This Validator check if there’s an input at all, and there is, it checks that the file path does exists. That’s about it.
There is a little “try… catch” that ensures that the Validator won’t fall on wrong arguments exception that the File class might throw once the arguments for it are… well… wrong.
That’s it really, you can see the code for the Validator and the usage of it below.
Notice that the instatiation and usage of the validator is made in AS code, though it can be done in the more conventional way, in MXML.
For any question or comment, you know where to find me.
Take care.


PathValidator

package com.flashmattic.validator.pathvalidator {
import flash.filesystem.File;

import mx.validators.ValidationResult;
import mx.validators.Validator;

/**
* This validator validates that a path given is a valid path for an existing
* file or folder.
* @author MBz
*/
public class PathValidator extends Validator {
public function PathValidator() {
super();
}

/**
* Checks for illigal arguments for the File constructor and also if the
* path given is valid and points to an existing file or folder.
* This also checks of any input was inserted, if the user decided that
* this field is requiered.
* @param value
* @return Array
*/
override protected function doValidation(value:Object):Array {
// Convert value to a String.
var inputValue:String = value as String;

// Clear results Array.
var results:Array = new Array();

var validationResult:ValidationResult;

// Call base class doValidation().
results = super.doValidation(value);

// Return if there are errors.
if (results.length > 0) {
return results;
}

if (required && (inputValue == null || inputValue == "")) {
validationResult = new ValidationResult(true,
null,
"no string",
"You must enter a path");
results.push(validationResult);
return results;
}

try {
var testFile:File = new File(inputValue);
if (!testFile.exists) {
validationResult = new ValidationResult(true,
null,
"path not valid",
"Invalid Path");
results.push(validationResult);
return results;
}
} catch (e:ArgumentError) {
validationResult = new ValidationResult(true,
null,
"path not valid",
"Invalid Path");
results.push(validationResult);
}
return results;
}
}
}


Usage

filePathValidator = new PathValidator;
filePathValidator.addEventListener(ValidationResultEvent.VALID, onFilePathValid);
filePathValidator.addEventListener(ValidationResultEvent.INVALID, onFilePathInvalid);
filePathValidator.required = true;

filePathValidator.validate(value);

May 22, 2009

OT: עוד הופעה בעיר הקדושה

כמה OT's אפשר הא?
אני יודע... יש כאלו המתמרמרים, אבל מה אני לעשות? יש התפתחויות מעניינות בתחום המוסיקאלי, ולמרות שה-validator חדש שכתבתי מרתק (את השועלים ואותי...) אני מרגיש הרבה יותר טוב בלבשר לכם על ההופעה הבאה שלנו, בהתרעה של "מהיום למחר?".
הלהקה שלי, TYPO, מופיעה בירושלים במוצ"ש הזה (כן, מחר. זה הקטע של מהיום למחר בד"כ). אנחנו מופיעים עם להקה מצוינת שנקראת the CarSitters, המקום נקרא Bass. ההופעה תתחיל ב-22:00.
תגיעו, מבטיח שלא יהיה דיסקו.

May 05, 2009

OT: הופעה נוספת באוזן!

כן, זהו עוד פוסט שלא קשור לפלקס. תתבעו אותי.
אז ככה, ללהקה שלי יש עוד הופעה ב"אוזן בר" במסגרת ערב מרובע של 4 להקות (וחצי, עוד רגע תבינו למה) שהקונספט שלו הוא סולניות עם להקות בועטות מאחוריהן. האירוע יקרה ב 15 לחודש מאי, כלומר החודש למי שזה לא חלחל עבורו, ביום שישי. לכל הספקנים הנה הלו"ז של חודש מאי, תעיפו מבט.
ת'כלס, ערב של רוק/אינדי טוב, להקות שבאמת שווה להכנס ל- MySpace שלהן ולהטות אוזן. עכשיו, החצי ממקודם הוא מופע חימום של רייצ'ל עזוז (כן, השם מעלה עווית על הפה, אבל בכיף) משהו אינטימי-סטייל עם פסנתר בקטנה, לפי מה הבנתי אמור להיות סבבה. וכמובן דיג'וי של יעל קראוס מהפאניק-אנסמבל (הטו, הטו אוזן) לאורך כל הערב, והכל כולל הכל בעבור 40 שקלין מצלצלין וטיבין.
למי שלא זוכר איך ומה, אתם מוזמנים לקפוץ ל- MySpace שלנו. וכמו שאומרים, נשמח לראותכם במיטב מחלצותיכם, אבזמי-אפכם ומיימית וויסקי.
קפצו ל- Facebook ותנו Attend.

לגבי פלקס, אל חשש אנשים. אני יודע שאני אומר את זה הרבה, אבל יש דברים בגו. יש לא מעט דברים חדשים שתוך כדי עבודה צצו, ואני רוצה לשתף אתכם בהם (אללא יודע למה...)
דב איתי, אוקי?
יאללא ביי.

March 26, 2009

OT: הופעה שלנו באוזן-בר

An English translation is available for this post...
מה המצב?
אז ככה,כמו שחלקכם אולי יודע יש לי הרכב (להקה קוראים לזה, אבל נו... מה עכשיו?) שנקרא "Typo". אתם יכולים לשמוע קצת צלילים מחזרות ב- MySpace שלנו. הסיבה שאני שם את זה פה היא שאנחנו מעלים הופעה ב-3 לאפריל, 2009, שזה יוצא יום שישי,באוזן בר, ככה לקראת חצות שכזה. זו הופעת טרום בכורה, קצרה וקולעת וחשוב מכל - חינאמית. אז אתם יכולים להתייחס לזה כהזמנה אישית.
בכיף.
יאללא ביי.
How's it going?
So as some of you might know, I have a band called "Typo". You can some of our stuff from rehearsals we did on our MySpace spot. The reason I'm telling you this is that we're giving a show on April 3rd, 2009, in a place called The Ozen-Bar, close to midnight. It will be a pre-premiere (… right) show, short and to the point and most importantly - free! So you can take this as a personal invitation.
Cheers.

February 21, 2009

You open, You see :: Label

An English translation is available for this post...
בהמשך ל"פותחים רואים" הפעם אני אתעכב על class שכולנו משתמשים בה תכופות ויכולה לעיתים למרוט את העצבים שאנו שומרים רק להפסדים של נבחרת הכדוריד של טורקיה: Label.
למי שלא מכיר, הקדמה קלה – Label זו מחלקת UI שבאה להציג טקסט בשורה אחת עם היכולת הנהדרת של חיתוך הטקסט במקרה ואין מספיק מקום עבור כולו, שירשור עם "..." ויצירת tooltip עם הטקסט המלא. זו פונקציונאליות לא רעה, בייחוד אם רוצים להציג מידע ב- DataGrid למשל, ומעוניינים בהתנהגות שמגדירה כי ברגע שמצמצמים רוחב של עמודה המציגה טקסט, הטקסט יחתך עם "..." ו- tooltip יופיע עבורו.
אז הנה שני דברים מעניינים שגיליתי תוך כדי נבירה במחלקה:
הראשון, אם נביט במתודת updateDisplayList נגלה שיד נסתרת מירקרה (ניטרלה את הקוד כהערה) האחראי ליצירת צבע רקע עבור ה Label. מדוע? לא ממש ברור, ואני יודע שיש מספיק חנאנות שבנו מגדלים רבים בכדי לספק ל- Label שלהם רקע, אז סאחבק הרים את הכפפה המעופשת והרחיב את המחלקה. לא עשיתי הרבה, שכן הקוד היה כבר שם. אני אשמח לדעת אם יש סיבה מסויימת לכך שהוא מורקר. את הקוד תוכלו למצוא בסוף הפוסט.
הדבר השני, שהטריד אותי הרבה יותר, הוא באג תמוה ומכעיס שיש ל- Label ושנוגע בדיוק בפיצ'ר המגניב שהזכרתי לעיל. אני אסביר: נניח שיש לנו container ברוחב מסויים ותחתיו יש לנו Label עם רוחב של 100 אחוזים. הדבר יתבטא בכך שה- Label יקבל את הרוחב של ה container. נקטין את ה container נקטין גם את ה Label, אתם מבינים את הרעיון. באופן מוזר, ברגע שלא מוגדר ל Label רוחב פיקסלי מוצהר, הטקסט שבתוכה מרחיב אותה בלי להתחשב ב- container בו היא נמצאת. רציתי לברר את הסיבה למחדל הזה שגורם לנו לפעמים ליצור כל מיני workarounds מטורפים (שגם שעולים בביצועים) ולמצוא פתרון יותר אלגנטי עד שהחבר'ה שם למעלה יתעוררו.
הסיבה למחדל הזה נעוצה בחישוב ה- explicitMinWidth של Label. כפי שאולי ידוע לכם, את המאפיין explicitMinWidth אנחנו לא מגדירים ישירות אלא ע"י השמת ערך למאפיין minWidth, מה שאומר שאם לא מגדירים minWidth אזי ה explicit min width לא מוגדר. תוסיפו למשוואה את העובדה ש- explicitMinWidth נדרש עבור חישוב גודל "הילדים" של container ויש לכם כבר שלושת-רבעי התשובה.
Label מחזיקה את UITextField בקומפוזיציה וזו אחראית (היא וכל אבותיה) על כל חישוביי הרוחב של תיבת הטקסט, חיתוך הטקסט וכיו"ב. כפי הנראה, ב- measure נעשה חישוב של רוחב תיבת הטקסט נכון לטקסט שבתוכה וגם ה minWidth מוגדר עפ"י אותו הגודל, משמע, היה לנו טקסט שרוחבו הסתכם ב 480 פיקסלים לצורך העניין, גם ה- minWidth של תיבת הטקסט יוגדר כ 480 פיקסלים. ואם ה minWidth מוגדר כך, אזי גם explicitMinWidth מוגדר כך. אין סיכוי שתיבת הטקסט תצטמצם נכון לcontainer שמחזיק אותה שהרי יש לה הגבלת מינימום של 480 פיקסלים. מרגש, לא?
בד"כ זהו המקום להוציא שלל דימויים עבור מי שקודד את האיוולת, אך במקום זאת אני אפנה לפתרון המיידי והפשוט. ברגע שאתם רוצים שה- Label יסונכרן ברוחבו ל container שמגדיר אותו, יש להגדיר את ה minWidth שלו ל-0. שכן, ברגע שמוגדר כבר ערך עבור explicitMinWidth פעולת ה set של minWidth פשוט לא עושה דבר. זה הכל.
אני מקווה שהשכלתם ומעתה תדעו יותר על מה שקורה בתוך Label. עד הפעם הבאה, עם מערכת חיסון חזקה יותר מכל הבחינות.
תיסלם.


In continue to “you open, you see” series, this time I’m going to talk about a class that we all know and use very often, yet it has the potential for killing us slowly as a result of a nerves breakdown: the Label.
For those of you who have no idea of what I’m talking about, here’s a quick brief – Label is a UI class that represents a text in a single line with the great ability to truncate that text if the space doesn’t allow all of it, adding a “…” suffix to it and a nice tooltip with the full text in it. This functionality is not bad at all, especially when you want to display a textual data in a DataGrid, and have a behavior that when the column is reduced in width, then the text within it will be truncated with a “…” suffix and a nice tooltip.
So here are two interesting things that I found out digging in that class:
The first, if we look at the updateDisplayList we shall find that a mysterious hand has removed the code that was assigned to handle coloring the background of the Label component. Why? Heavens knows. I do know that many geeks have built many extensions to overcome not being able to color the background of Labels, so I’ve decided to take this small opportunity and extend the Label class. Actually, I didn’t do that much. The code was already there, but commented out. I’ll be glad to know if there is a reason for commenting this out in the first place. You can find the code at the end of this post.
The second thing that bothered me even more, is the weird and annoying bug that Label has right where the nice feature I mentioned above is. I’ll explain: Say we have a Container bearing a certain width and residing in it we have a Label with the width of 100%. This means that if we reduce the width of the Container then the Label’s width will act accordingly and be reduced as well. Strangely, when you don’t set a specific pixel width to the Label, the text inside it stretches it without caring about the width defined on the parent Container. I wanted to realize why this happens, this which cause us sometimes to come up with weird workarounds (that are also expensive performance wise), and find a more elegant solution to it until the guys upstairs wake up (maybe they did, in Gumbo?).
The reason for this bug is due to the calculation of the explicitMinWidth member. As you might know, we can’t directly set the explicitMinWidth member, but instead we define it by defining the minWidth member. This means that if you don’t define the minWidth then you’re not defining the explicitMinWidth as well. Adding to this equation the fact that a Container relies on explicitMinWidth to measure its children and you already have three-fourths of the solution.
Labels holds UITextField in composition, which is responsible (with its ancestors) for all the text field sizing calculations, text truncations and the rest. As it seems, the width calculation of the Label’s text field is done within the measure method of the Label class. Inside that method the minWidth is set for the component according to the text measurement I’ve mentioned before, so if our text width is 480 pixels, the minWidth of the Label component is set to 480. If the minWidth is set to 480 pixels so is the explicitMinWidth. There is no way that the parent Container of the Label will be able to cast it’s width on it, since we have a 480 pixels minimum width constraint on it. Exciting, isn’t it?... oh man.
Usually this is the place I reach for the sickest metaphors I have in order to describe to ones who coded this monstrosity, but let me spare you with that and go directly to the simple solution. When you want the Label to be in synch with its parent Container width, simply put 0 as it’s minWidth because, when there is a value set to the explicitMinWidth the minWidth setter does nothing. That’s all.
I hope this helps you and you now know a bit more about what’s going on inside the Label class. Until next time, take care, guys.

package com.flashmattic.underthehood.labelex {
import flash.display.Graphics;

import mx.controls.Label;
import mx.styles.StyleManager;


/**
* Color of the Label object's opaque background.
* The default value is undefined,
* which means that the background is transparent.
*/
[Style(name="backgroundColor", type="uint", format="Color", inherit="no")]

public class LabelEx extends Label {
public function LabelEx() {
super();
}

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);

var g:Graphics = graphics;
g.clear();
var backgroundColor:* = getStyle("backgroundColor");
if (StyleManager.isValidStyleValue(backgroundColor))
{
g.beginFill(getStyle("backgroundColor"));
g.drawRect(0, 0, unscaledWidth, unscaledHeight);
g.endFill();
}
}
}
}

February 05, 2009

Flasher :: New Mag

An English translation is available for this post...

כן, אני יודע ששוב לא כתבתי הרבה מאד זמן, אבל שלא יעלה מורא בליבכם – אני המשכתי לכתוב קוד כמו ילד שדופקים לו מכות בין ביס לביס בפיתה של ארוחת עשר.
'תכלס, כל מה שאני בא לומר הפעם הוא, שמצאתי איזה מאגזין פלאש/פלקס חמוד לאללא שעשוי גם לא רע בכלל (יחסית לחובבן) ו... ואללא, שווה צפייה. יש שם ראיונות עם אנשים טובים שעושים קוד טוב, יש שם דאחקות וצחוקים של חנאנות יש שם מידע כמובן. תנסו: Flasher.

Yeah, I know I haven’t been writing for tones of time but fear not for I still coded my arse off like a beaten up boy at school lunch break.
All in all, all I came to say is that I found this nice new Flash/Flex Magazine on the web which pretty cute, nicely made (even for an armature mag maker) and… worth a look. There are some nice interviews with people from the scene, some geeks laughs and information of course. Give it a go: Flasher.

November 22, 2008

? Who asked the profiler to butt-in

An English translation is available for this post...

אחרי תקופה קשה בה הבריאות הרופפת שלי החלישה כל נים אפשרי, החלטתי שהגיעה העת להעיף מבט שוב למחשב ולבטל איזה מעופף טורדני שהקפיץ לי exceptions בדיבאג.
מה שקרה הוא, שבכל פעם שבאתי לדבג, עפה לי הודעה שה- profilerAgent.swf לא מצליח להתחבר בעקבות בעיית security sandbox, בעוד אני יושב שמוט לסת ולשון כששאלה אחת רצה 100 מטר משוכות בראש שלי: מי בכלל, לאלף עזאזלים, ביקש מהפרופיילר הזה להרים ת'ראש שלו?!
אמרתי לעצמי, שעכשיו אני מגגל על זה ומוצא את ההסבר לתופעה. תופעה, שאגב, החלה ברגע ששדרגתי לנגן 10 הידוע יותר לשמצה בכיניו "אני עוד אגיע לכל הפיצ'רים שלך, רק תן לעבוד קודם". פי-פאם-פו היגעתי לאיזה פוסט מעניין ששמט לי את הלסת עוד יותר, בבקשה לקרא.
נו? מה תגידו?
מסתבר שנשארה שורה בקובץ ה mm.cfg (ההוא שרושם לוגים של פלאש אם הוא ממש במצב רוח טוב). שורה פשוטה שאומרת לפרופיילר להרים את הראש שלו ולנסות להתחבר, בלי שום קשר לאם ביקשנו או לא. כמה פלקסי מצידו, הא?
אם מוחקים את השורה הזו הכל חוזר לסורו. כאשר מרימים את הפרופיילר, השורה נרשמת שוב וכאשר מרימים רק את הדיבגר, השורה הזו נמחקת כלא הייתה.
אז בכל מקרה, אם נתקלת בגוגל-מוגל הזה, אתם יודעים מה לעשות.
שבוע טוב.

After a long time in which my poor health has weakened any possible vain, I’ve decided that it is time to have a filtering glimpse over my PC and deal with some flying annoying pest that keeps on popping those exception windows when I debug.
What happens is that every time I debug, an exception pops up that the profilerAgent.swf can’t connect over a security sandbox violation (don’t you love it?). While I’m still on my chair with my mouth wide open, one question kept racing the marathon in my head, going: who, for flex sake, has asked to profiler to raise its head and connect?!
I decided that it’s time to google that pest and find the solution for this phenomenon, a phenomenon that BTW begun the moment I upgraded to Player 10, better known by the name of “I will get to all you feature, just let me work first”. After a few searches I came to some interesting post that got my mouth to open even wider. There you go, read it.
So? What can you say about that, huh?
As it appears, there is a lost line left on the mm.cfg file (you know, the one that registers flash logs if it’s in a really good mode). This line simply tells the profiler to raise its head and connect, regardless if we’ve asked for it or not. How Flexi of it, right?
If you delete this line then all goes back to normal. When the profiler is bootstrapped the line registers again and when the debugger is bootstrapped then the line is erased.
So anyhow, if you encounter this lovely swamp you know what to do.
Have a great week.

November 12, 2008

OT: ירושלים

אני לא אתחיל לקדוח לכם בשכל על כמה אני אוהב את העיר הזו, אני פשוט רוצה להעיף איזה גיץ של שמחה על בחירתו של ניר ברקת כראש העיר של הבירה שלנו.
לפעמים זה נשמע אבסורדי, אני יודע... "ירושלים, בירת ישראל" שתכלס אנחנו יודעים שהיא, גג, בירתם של כל אלו שלא הצליחו לנוס על נפשם ממנה, ואלו שעסוקים בלהניס אותם. הצביון החרדי שהעיר החלה לקבל עוד מימיו של אולמרט פשוט גרם לעיר היפה הזו לאבד לפחות 6 קבין של יופי. זה רק הולם את העם הבוחר שלנו, לקחת סיפור כישלון במישור המוניציפלי כמו אולמרט ולהעביר אותו למישור הלאומי. משם עברנו ללופוליאנסקי שתרם רבות לעיר בכך שהחליף את שלט הכניסה לירושלים בחתיכת פח-צפרדע ירוק ושעון כניסת-שבת. הרכבת העילית עדיין מחכה כמו העבודת שורשים שלי, שמישהו יסיים אותה ודי. זה היה די ברור לבוחרים החילוניים בעיר הקודש, שאם הם לא יצאו מהספות אח-גדול שלהם העיר הזו תהפוך במהרה לסרט המשך רע לבני-ברק.
ניר ברקת? לא ממש יודע כמה הוא יכול להרעיד את האדמה הקדושה של העיר ולהפיח בה חיים, אבל אני בטוח שהעיניים שלו נשואות לכיוון הזה. בוא נתחיל בלעודד בניית מפעלי הייטק בעיר הקודש, ליצור איזשהו כוח משיכה לצעירים לחזור לעיר ולהקים בה חיים. בוא נסיים את הרכבת המזדרגגת הזו ונפתח כבר את רחוב יפו (וכמובן נשלם פיצויים לבעלי העסקים שם, שפשוט דרכו עליהם כמו על בדלי סיגריה). אני לא מצפה שעכשיו אדון ברקת ינהל את העיר כמו צ'קפויינט, אבל עדיין... שיכניס מעט ענווה ויוקיע את השחיתות החרדית (כן, קראתם נכון) שהתנהלה בעיר עד כה. שחברי מועצה יכבדו אחד את השני.
אם התקוות יתממשו, יש מצב שאפילו עבדכם הנאמן ישים את ירושלים כאופציה, וכמוני עוד לא מעט שנשבר להם הפופיק מהתחליפים הזולים והמלוכלכים שיש למדינה להציע.
מר ברקת היקר, לא נותר לי אלא לצטט את שמגר מ"גבעת חלפון" ולומר: "לעסק, סרג'יו, לעסק...". וקריאת "יש!" קפוצת אגרוף של מי שאוהב את העיר שלו, לא בגלל דוד המלך, אלא בגלל שנולד שם.

November 03, 2008

ServiceAdapter in BlazeDS – Where’s the service?

An English translation is available for this post...

"כיף".
לו הייתה ניתנת לי מילה אחת בכדי להגדיר את המעבר מ-LCDS ל-BlazeDS הייתה בוחר במילה הזו – "כיף". טוב נו, זה לא כזה נורא, אבל עדיין אדובי מצליחים להכשל בעקב אכילס שלהם שוב: הדוקומנטציה.
למרות שהכל די שקוף לאימפלמנטור (אני, אני...) ומעבר להברחות jar-ים מפה לשם והגדרות תלויות, מגיעים לשינויי-קוד, שהם למעשה הכואבים מכל.
בזמנו יצרתי הרחבה של ActionScriptAdapter עבור יישום של צ'אט באפליקציה. אותה המחלקה ניהלה את ההודעות בצורה מעט שונה שלא רלוונטית לעניין כרגע. מה שכן, המחלקה השתמשה במשתנה שהגיע אליה בירושה מאדון ServiceAdapter שנקרא בפשטות service.
קימפול זריז וג'אוה צועקת שהיא לא יודעת מי זה service ולא מכירה אותו אפילו ב"שלום שלום". מיד כשועל מנוסה אני קופץ אל התיעוד של אדובה בכדי לגלות מה העניינים. אני אכן מגלה שאין חיה שכזו service ב- ServiceAdapter, אבל להפתעתי אני מגלה דוגמת קוד שעדיין משתמשת בו כאילו כלום לא קרה. לא מאמינים? הנה תראו. אז מה בעצם נותר לנו? נכון. לפנות לפורומים.
חיפוש זריז ואני עולה על הת'רד, בו נאמר כי שהדוגמה היא קלוקלת ולמעשה יש דרך אחרת לפנות ל- service הנעלם.
אני מאד מקווה שאדובה מודעים לאיוולת הזו, שבטח מבזבזת לא מעט זמן למפתחים ברחבי העולם.
עד העונג הבא.

“Fun”.
If I had one word to define the migration from LCDS to BlazeDS, I would choose this word – “Fun”. Well, it’s not like it’s all that bad, but still Adobe manages to fail when they are known to fail in the most: Documentation.
Even though that most of it is pretty transparent for the implementers (me, myself and I…) and after smuggling all the .jar files and messing around with dependencies, we reach to the code migrations which hurt the most.
At the time I’ve created an extension for ActionScriptAdapter for a chat in the application. This class managed the messages that came through it in a slightly different manner that’s not relevant to the story. What’s relevant is that this class used an inherited variable called “service” that came from Mr. ServiceAdapter.
A swift compilation and Java shouts that it doesn’t know who “service” is. I instantly dive into Adobe’s documentation to see what the hell is done wrong here, and I do find out that there’s no such thing as “service” on ServiceAdapter, but to my utter surprise I also see a nice code sample which uses it. Don’t believe me? See for yourselves. So what have I got left? That’s right… forums.
After a quick search I find this thread where it says that the code sample is wrong and misleading and there’s another way to reference the “service” variable.
I very much hope that Adobe is well aware of this mistake that surely waste time to a lot of developers around the world.
Till next time…

October 26, 2008

Date Formatter gets hours wrong

An English translation is available for this post...

משהו ששווה לזכור.
לאובייקט Date, ברגע שרוצים להציג אותו בצורה מעט יותר עדינה מ- timestamp, משתמשים ב- Formatter שיודע לקבל format string ומשם לפרמט אותו לפיו. אתם יודעים על מה אני מדבר - MM:DD:YY וחבורתו.
הקטע קטע מגיע שאנחנו רוצים לפרמט את השעות. את השעות אפשר לפרמט, בין היתר, בדרכים הבאות: HH, ו-JJ.
HH, מספר לנו על יום שבו השעות הן 1-24, בעוד ש-JJ מדבר על יום שבו השעות רצות מ 0-23.
זה נכון ש-HH תהיה הבחירה האינטואיטבית של כל בר-דעת (שכן, מה בדיוק JJ אמור להביע, just-joking?), אבל אם תבקשו HH, לעיתים תכופות תגלו שזה לא ממש מה שהתכוונתם אליו, ופתאום יש לכם הבדל של שעה סוררת. זה קצת מקומם אם לקוח שלכם אמור להגדיר פורמט בו הוא רוצה לראות תאריכים, ומגלה שהשעון לא מכוון, כי הוא חשב (ובצדק, לעזאזל! בצדק!) ש-HH זו הבחירה הנכונה.
אדובה...? רוצים לספר לנו משהו שאנחנו לא יודעים?

Here’s something that is worth remembering.
When you want to display the Date object in a more easy-to-understand manner than timestamp, you use the DateFormatter that receives a formatting string ant act accordingly. You know what I’m talking about – MM:DD:YY and their gang.
The trouble comes where we want to format the hours as well. This can be easily done, mong other formats, in these ways: HH and JJ. HH will be a day where the hours go from 1 to 24 and JJ will be a dat where the hours go from 0-23.
It’s true that the intuitive selection of anyone who claims to have a brain would be HH (since, what exactly does JJ stands for, Just-Joking?), but if you ask for HH in your format string you will often find that it’s not really what you meant for and suddenly you have a one hour difference. To be honest, it pretty annoying when one of your customers is trying to define her own date format, only to find that the hours are not synched, cause she thought (rightfully, god-damn, rightfully!) that HH is the right choice to make.
Adobe? Care to tell us something we don’t know?

October 05, 2008

OT: ההופעה של AIR

כן, עוד OT. אל חשש, יש בדרך כמה פוסטים שיזגגו כל עין של מפתח תוכנה נחנח. יהיה בסדר...
ומה על הפרק? ההופעה של AIR, שהתקיימה ביום חמישי שעבר והייתה מפח-נפש עדין.
נתחיל מהיסטוריה - את AIR אני מכיר פחות או יותר משנת 98' של המילניום הקודם. התקליט שלהם, Moon Safari נטחן במקום העבודה שלי דאז, עד שלבסוף ייבש לשאר הקולגות את הנוירונים. מה אני אעשה? הנעימות שלהם הזכירו לי שני דברים שקרובים מאד ללבי: פינק-פלויד ו- Atari.
אני לא חשבתי שהם יגיעו לארץ, וגם אם המחשבה הזו חמקה בזריזות למוחי, לא ממש האמנתי שאני אלך להופעה שכזו. בכל אופן, נפל דבר ומצאתי את עצמי צובא על דלתות האנגר 11 בנמל, יחד עם האנשים היפים של תל-אביב. כרגיל ולפי המתכונת, התור לכרטיסים היה מאורגן כמו גשר המכבייה. פה שם, נכנסנו לאולם הגדול וחכינו לייבוש הגדול הנקרא "מתי הם יעלו כבר, יא אללא שלהם?". סביבות 22:45 הם עולים. שלושה חברים, שני צרפתים מהודקי חולצה ומכנס ומתופף שמנמן.
ההופעה התחילה עם שיר שלא הכרתי (אבל אין דבר, עוד הרבה כאלו יגיעו...), במין פסנתר, גיטרה, תופים שכזה. סתם. שאר ההופעה נמשכה בין שירים מוכרים יותר לפחות, בלי הרבה פירוטכניקת-אורות (אם בכלל) ופחות מזה כריזמה של הזוג. שני הצרפתים בקושי דיברו עם הקהל, וכשעשו זאת, השתמשו באפקט ה"רובוט" שיצא מהאופנה בערך בזמן שתמי בן-עמי (ז"ל) הייתה רלוונטית. ומילא להשתמש בקול הרובוטי פעם אחת, אבל לשמוע שוב ושוב "Thank you Tel-Aviv" ככה... ראבק בנאדם, תקנה לגו, רק עזוב אותנו.
ככה נעמדנו בין השירים, בלי להתרגש יותר מדי והאזנו לסאונד הנוראי שהאנגר 11 יודע לייצר. אני לא מבין איך אפשר לנהל שם הופעה. גם כשהייתי בפרודיג'י הסאונד היה נוראי שם. לא למדנו שום דבר? יש מצב שהאנגר, שהוא למעשה אולם-פח, לא ממש מתאים להופעות בהן כל תו חשוב? ונגיד שהיה סאונד סביר, אוקיי? הצמד השמיט המון "קטנות" מהשירים. "קטנות" שעושות את השירים והקטעים למה שהם. זה היה כמו גרסאת כיסוי מאד מהוקצעת, אבל חוטאת למקור.
איכשהו הגענו להדרן הראשון. מחיאות כפיים ושריקות מקהל שבאמת בא לתת את כל מה שיש לו ונתקל בשני באגטים עבשים (ומתופף שמנמן), והנה הם עולים ומבצעים שירי צאן-ברזל כשהם מסיימים ב- La Femme d'Argent, ורק שם הם נתנו את מה שהקהל רצה מתחילת ההופעה: "בום!". הפציצו בפסיכודליה, העיפו את התאורה לאוויר, יצאו באילתורים וזה בדיוק מה שהיה חסר כל ההופעה!
ואז הם ירדו.
אשכרא הדליקו את הקהל, נפנפו לנו מול הפנים ב"תראו מה יכל היה להיות אם לא היינו זורקים עליכם" וירדו מהבמה. שום תשואות לא החזירו אותם חזרה, ותכלס? אם היה לי בקבוק בירה ביד, אולי הוא היה מוצא עצמו במאך 5 לכיוון הבמה. 75 דקות של הופעה מאכזבת עם שיאים של גג משגל-פנסיונרים. שיקחו את קול הרובוט שלהם ואת המתופף השמנמן ויגלשו על טיל הישר לצרפת. עדיף לשים דיסק באוטו.
בהחלט אכזבה. AIR הם לא הרכב של הופעות (לפחות לא בארץ) ושימשיכו לעשות את מה שהם עושים טוב, ולא לגבות כסף על חזרות עם קהל.
עד העונג הבא.

September 29, 2008

OT: שנה טובה לדוד גיבור

מה קורה, מתקתקי-קוד אפרפרים?רק רוצה לאחל לכם שנה טובה, אבל לא שנה טובה של החברים שאתה לא רואה מאתיים שנה, ופתאום מפליצים לך SMS קבוצתי של "אושר והגשמה", אלא שנה טובה מהלב, וזה הולך ככה:
קודם כל בריאות, שזה חשוב וגם קופ"ח חונקת בכספים, אז חבל... ואז אחרי הבריאות שיבוא גם האושר, אבל אושר אמיתי שבא מיצירה, או אהבה או... בורקס טוב. סביח זה לא אושר, סביח זו מלחמה קולינארית. איפה היינו? אה! ממון, כי זה נחמד שיש מרשרשין בכיסים, לכל המשקיעים בבורסה אני מאחל שנה נטולת ריצות אחר הזנב של עצמכם, שתמצאו במה להשקיע ושתפסיקו להאמין שלדבר על כסף באמת עושה כסף. אהבה זה חשוב, אז שהאהבה תהיה שם, לא פושרת, לא דרדל'ה, אלא ממש אהבה כזו שמותחת חיוך גם על איטונג. ולאלו שכותבים קוד, שתהיה לכם שנה של פחות re-factoring, שנה של פחות באגים ויצירתיות. ולמוסיקאים שבנינו, שנה של פלייליסטים שווים, חוזים בחו"ל והופעות מלאות.
שמחות על ראשיכם,
חג שמח ושנה טובה!

September 20, 2008

Custome Metadata tags for Flex :: keep-as3-metadata

This Hebrew message will be followed by an English one...

הטריף לי את השכל, הקטע הזה, הארגומנט הממזר הזה של MXMLC (ו- COMPC) שנקרא בפי חבריו: keep-as3-metadata. אם תקראו בקצרה בדוקומנטציה (שכמו תמיד לא מאכזבת ולא מספרת שום דבר יעיל) תלמדו שאם אתם רוצים לשמור תגי metadata שלכם, כך עושים זאת. לא ממש מפרטים מי, מה, איך להוציא את הפרטים של אותו התג ב-runtime... לא... למה שפרטו? אנחנו, כרגיל, ננחש.
האמת? את העניין גיליתי תוך כדי הצצה לעבר framework שנקרא Swiz (שווה הצצה, אבל לא מספיק בכדי לצאת לרחוב בצעקות "הידד!"). ב- Swiz משתמשים בשני תגי metadata של ה- framework שהם לא קשורים לאלו המוגדרים מראש בפלקס, וזה הביא לי בסקרנות – האימפלמנטציה, השימוש, אז פתחתי ונברתי מעט בקוד של Swiz ויש לפני את הבשורה.
לפני שאני אפרוש פה קוד, אציין שהשימוש, במתכונת הנוכחית, הוא מעט בזבזני ולא אלגנטי. אני מקווה שבעתיד תהיה אופציה הרבה יותר טובה ליישם את העניין. ובכן, לעסק:
ראשית, בואו רגע נתעכב על ()describeType. המתודה הזו יודעת לקבל אובייקט ולהחזיר אובייקט XML עם כל המאפיינים ה- Public של אותו אובייקט. ה-XML הזה גם מכיל גם את ה-metadata עבור כל מאפיין. יש כמה וכמה כלים לפלקס שבנויים על היכולת הזו. סבבה לנו? למה לא.
עכשיו, בכדי לאפשר את תגי ה-metadata הנוספים מוסיפים ארגומנט לקומפיילר העונה לשם keep-as3-metadta. כך שאם אנחנו רוצים להוסיף metadata בשם flashmattic, נכתוב:

-keep-as3-metadata+=flashmattic

למה =+? כי אנחנו לא רוצים להיות חצילונים ולמחוק את כל מה שכבר מוגדר.
מה שעכשיו קיבלנו הוא, שבכל הגדרה שנכתוב בה את [flashmattic], נקבל את את ערכי ה-metadata ב-XML של ה describeType. את ה metadata נכתוב כמו כל metadata אחר:

[flashmattic]
public var inputTxt:String;

אנחנו יכולים להוסיף גם מאפיינים ל- metadata, כך:

[flashmattic (value=”Matti”)]
public var inputTxt:String;

זה מגניב, אבל לא ממש עוזר לנו. את כל זה יכולנו לעשות גם בלי הטובות של הקומפיילר והארגומנטים שלו. או! אז פה הטעות, שכן מבלי להוסיף את הארגומנט המוזכר לעיל, הקומפיילר לא יודע לקרא את ה-metadata הזה ולהכניס אותו אל הפרטים ב-XML של describeType.
מה שנותר הוא לקרא את הנתונים הללו, להוציא מהם את מה שאנחנו מחפשים וכך, ב runtime נוכל ליישם dependency injection למשל. הנה אמפלמנטציה אחת לדוגמה:

private function resolveDependencies(accessorList:XMLList):void {
for each (var dependee:XML in accessorList) {
if (dependee.metadata != undefined && dependee.metadata.(@name== "flashmattic") != null) {
var meta:XMLList = dependee.metadata.(@name == " flashmattic");
if (meta.arg.(@key == "value") != null && meta.arg.(@key == "value").@value != undefined) {
trace(meta.arg.(@key == "value").@value); // Traces “Matti”
}
}
}
}

לא רע, הא? מה שכן, לכאורה נראה כי הריצה בלולאה על כל המאפיינים עולה בשן ועין בביצועים, אבל לאחר בדיקה קצרה, נראה כי הזמן זניח (16 מילישניות עבור 2 קומפוננטות מקוננות). אני עדיין צריך לבדוק את זה בפרויקטים בעלי נפח יותר גדול.
בכל אופן, מקווה שזה מגניב אתכם כמו שאותי, אחרת אני ממש יוצא פה חננת-מחשבים...
שבוע טוב שיהיה :).


This little thingy drove me insane. That elusive MXMLC (and COMPC) argument, well-known to his fellow arguments as “keep-as3-metada”. If you read the documentation about it (that never loses an opportunity to fail in description), you’ll learn that if you wish to keep your own metadata tags, this is the way to do so. They don’t really say who, where or how to get those details at runtime. We’re left guessing…
To be honest, I first discovered interest in this issue when reading about the “Swiz” framework. In Swiz there are two extra customized metadata tags involved, and that made me curious about the implementation and usage, so I lifted the hood up and looked under it.
Now, before I give you my resolutions, I must admit that what Swiz is doing is a bit expensive performance-wise. I hope that this way of implementation will be made more elegant in the future of Flex SDK. Well… let’s dive into it:
First of all we want to check out this nice method called “describeType()”. This methods expects an object as its argument, and return an XML object with the details of all public properties in this object. By the way, Many Flex tools rely on this feature. Are we happy so far? Sure we are.
Now, in order to enable extra customized metadata, we need to add the keep-as3-metadata argument to the compiler, so say we want to add “flashmattic” as our new customized metadata, we’ll add the following to the compiler arguments:

-keep-as3-metadata+=flashmattic

Why +=? Cause we don’t want to be complete numb-nuts and override the predefined metadata tags.
What we have now is, whenever we add the flashmattic metadata tag to any public property of an object, the XML retrieved from the descibeType() method will include that metadata and it’s properties. We add the metadata to our like any other metadata in flex:

[flashmattic]
public var inputTxt:String;

We can also add some properties to our metadata tag, so… let’s add a property to our metadata:

[flashmattic (value=”Matti”)]
public var inputTxt:String;

This is nice, right? Yeah, but we could have done this without asking the favors from the compiler and its arguments. Wrong! Not adding the metadata to the compiler, will cause the descibeType() method to avoid it and not have its details to the XML.
What’s left for us is to run trough that XML at runtime, find our metadata and retrieve the information from it. This is highly useful when wishing to implement dependency injection in Flex. Here’s one example:

private function resolveDependencies(accessorList:XMLList):void {
for each (var dependee:XML in accessorList) {
if (dependee.metadata != undefined && dependee.metadata.(@name== "flashmattic") != null) {
var meta:XMLList = dependee.metadata.(@name == " flashmattic");
if (meta.arg.(@key == "value") != null && meta.arg.(@key == "value").@value != undefined) {
trace(meta.arg.(@key == "value").@value); // Traces “Matti”
}
}
}
}

Not bad, ah? Well, apparently, going through that loop looks a bit expensive as I mentioned before, but after running a couple of tests it looks like it will not affect the player that bad (16ms for 2 nested components), but I need to test it on a larger project to make sure that this implementation won’t add to the already bad performer we call Flash Player.

September 18, 2008

Flashoo Convention on the 25th

This Hebrew message will be followed by an English one...

אנשים יקרים,
רק רוצה להזכיר לכם שכנס פלאשו, בתמיכת אדובי עם כל המשתמע, יערך ב-25 לספטמבר! בכנס יוגשו הרצאות (לצערי, לא ארצה הפעם מפאת חוסר זמן), פרסים ואנשים טובים... שלא יוגשו אבל יהיו נוכחים. מה רע?
אז אם עדיין נשארו מקומות, הרשמו עכשיו! יש גם בקישור את כל הפרטים הנוספים על איך להגיע וכו'...
הנה הת'רד הפלאשואי.
נתראה שם :).

Dear people,
I just wanted to remind you that Flashoo is throwing a convention, supported by Adobe, on the 25th to September! Lectures will be given, awards and good people to meet. Now how ‘bout that?
So if there are still places left, make sure you register now! The link also has details about the location and more…
Here’s the Flashoo thread as well.
See ya there :).

September 16, 2008

OT: ריצ'ארד רייט הלך לעולמו


ואללא... יודעים מה? גם כשאני כותב את זה אני לא כל כך מאמין שזה קרה. רק לא מזמן, כמו שאתם קוראים, כתבתי על ההופעה שלו יחד עם גילמור ועכשיו... ואללא... אין לי ממש מילים.
אני חושב שהוא היה החבר היחיד בפינק פלויד שהתקרב למוסיקה מעט יותר מורכבת מאשר בלוז 12 תיבות. תמיד ששרים את ה- Desperation is the English way, נראה לי שזה נכתב עליו (אולי כי הוא גם שר את זה... לך תדע). בכל מקרה, זה יום עצוב. אתם יכולים לצחוק ולחשוב שאני סתם מזיין בשכל, אבל זה יום עצוב.
Bm7-Fmaj7.

September 08, 2008

Imporganizer :: Removes redundant imports

This Hebrew message will be followed by an English one...

יש קטע שמעורר את חמתי ברמות של בוחן פתע. אתה מריץ לתומך חיפוש על כל הפרוייקטים בכדי למצא איפה משתמשים במחלקה מסויימת, ואתה קולט שיש איזה 200 מופעים שלה, מה שמגניב לך את העין והראש, שהרי אין מצב שיש כל כך הרבה, ומאידך אם יש זה אומר שאתה צריך עכשיו לשנות 200 מקומות.
אחרי שאתה משלים עם מר גורלך ורוע הגזרה אתה מתפנה לסדר את העניינים שלשמם התחלת את החיפוש, ולהפתעתך (שלא לדבר על מורת רוחך) אתה מגלה שרב התאימויות הן על imports. כפי שודאי אתם מניחים, עם Imports שאף אחד לא משתמש בהם באותה המחלקה.
מקומם.
אז החלטתי שאני אארגן איזה כלי, ועל הדרך גם אלמד להשתמש ב file accessibility של AIR, שכל התפקיד שלו יהיה לעבור על עץ הפרוייקט בצורה רקורסיבית ולהעיף imports שפשוט לא צריכים.
לפניכם התוצאה, אבל לפני שאתם קופצים להוריד ולהשתמש הסתייגות קטנה וחשובה:
את הנסיונות הראשונים יש לעשות על פרוייקטים וקבצים מגובים. השימוש הוא על אחריותכם בלבד!
עכשיו אתם יכולים להוריד אותה מפה.
דבר אחרון - אני מאד אשמח לכל בקשה, תהיה, באג שתמצאו (פחות, נו..) ובכללי, אני מגיש את ה Imporganizer הזה חיני-חינם, אבל אשמח אם תוכלו לפרסם פה כמה imports נוקו מהפרוייקטים האישיים, ככה... בשביל לעשות לי טוב על הלב.
סלאמת.

There's this thing that really makes me furious, in a pop quiz levels. You run an innocent "search" on your projects, to find where a certain Class is being used, and you get like 200 instances of that class, which totally freaks you out since there's no way that your projects holds that usage, but on the other hand now you need to check 200 places to make the fix you need to do.
After you've excepted your poor fate you clear the table and starts to fix the stuff you initially made the search for, and to your surprise (and anger) you find that most of the matches are unused Imports in your classes.
So... I've decided that I will get this tool going, and on the way learn about AIR file accessibility, that will simply go over recursively on a project tree and clean all the redundant imports it holds.
The result is before you, but before jumping to install and try it, a small but highly important disclaimer: Your first attempts should be made on a backed-up files. You are using it at you own risk!
Now you can download it from here.
One last thing - I will look forward to any request, tought, bug (well... a bit less but still), and in all, I'm serving the Imporganizer free of charge with just one request from you guys - please let me know if it helped you in any way, how many imports did it remove and so on... you know... :).
Cheers

September 07, 2008

Flashmattic going international

This Hebrew message will be followed by an English one...

כן, אני יודע... אתם וודאי מחכים למרכזנית שתכריז, שבכדי לדבר עם איש המכירות צריך להקיש 1.
מה שקורה הוא דבר שכזה: יהיו פוסטים שיפתחו בשורה שפותחת, למעשה, את הפוסט הזה. מה שזה אומר הוא, שהתוכן של הפוסט יובא גם בעברית וגם באנגלית וכל זאת בכדי לא לקפח את הקוראים הבינלאומיים שמאד רוצים לדעת למה יש להם באג, אבל לא ממש מבינים את הערבסקה שנקראת עברית. בכל אופן, ברוכים הבאים תושבי הנכר, מקווה שתמצאו את התוכן מעניין ומועיל.
יאללא סאלאמת (עכשיו... איך מתרגמים "סלאמאת" בדיוק?).


Yeah I know... You're probably waiting for the operator to tell ya that in order to talk to the sells-person you need to dial 1.
What gonna happen is the following: There will be post that will be opened with, in fact, the line that opens this post. What it means is that the content of this post will be brought not only in Hebrew but also in English as well, and all this to not neglect the international readers who might very much like to know why they have a bug but don't really understand the arabesque called "Hebrew". In anyway, welcome people abroad, I hope you'll find the content interesting and useful.
Peace out.

August 29, 2008

פותחים-רואים :: Spacer

ראשית, הקדמה:
הפוסטים שיפתחו במילים "פותחים-רואים" למעשה יתארו נושאים בצורה הרבה יותר פרטנית, חודרנית (מי מחייך?) ופשפשנית. מה שהחבר'ה נוהגים לקרוא לו: Under The Hood, אבל כמובן אנחנו, שגדלנו על הגשש ומוכסכניקים מפוייחי-ידיים, לא יסמאו את עיניינו עם מושגי-שפר אמריקאים. יש? לעסק...
Spacer היא קומפוננטה קטנה שכל היעוד שלה בחיים הוא כזה: לעשות רווח (מפתיע, אני יודע). משתמשים בה בעיקר כאשר רוצים לעשות... רווח.
אוקיי, אני חושב שזה מספיק.
בכל אופן, אם נסתכל מעט פנימה נראה שכל מה שה Class שנקראת Spacer עושה היא להרחיב את UIComponent. זהו.
לא באמת... זהו.
עכשיו, מה שיותר מעניין היא השאלה "מה הוא ההבדל בין שימוש ב UIComponent במקום Spacer?". לכאורה, התשובה אמורה להיות "שום דבר", אבל לא ממש.
ניסוי קטן בהשוואה בין השניים מניב את התוצאות הבאות: 100Bytes~ לטובת השימוש ב UIComponent (כלומר, שמשתמשים ב UIComponent התוצר קטן יותר בנפח). כעת, יש את אלו שיגידו ש"מה זה 100 bytes?", אבל תחשבו על זה ככה - 10 Spacers נהיה כבר Kb... לא נעים, לא חבל?
תכלס? לא כזו רעידת אדמה, אבל שורה תחתונה היא, למה לא תשתמשו ב UIComponent במקום? חבל על כל טיפה.


August 25, 2008

DateField.selectedDate נותן בצנרת

זו לא סתם גסות, זו האמת לאמיתה.
מדובר כאן בבאג די ידוע שמצליח לגזול לי שוב ושוב דקות יקרות מכיוון שבכל פעם זה נראה לי כל כך לא נכון מכדי לקרות, אבל בכל זאת... התרחיש הוא טריוויאלי לחלוטין:
יש לנו DateField ואנחנו רוצים לחבר אותו ב binding אל תאריך שנמצא במודל שקר-כלשהו, בשאיפה (לגיטימית) שברגע שזה ישתנה, כך גם תשתנה הבחירה בלוח-שנה החמוד שנפתח מה DateFeild. שאיפה? חצבת! אני משנה ושמשנה את התאריך אבל הלוח-שנה לא מסמן דבר וחצי דבר. מקומם... מקומם מאד.
אז עשיתי חיפוש מהיר, גם כי זכרתי שכבר נתקלתי בתלאה הזו בעבר, והנה גיליתי את המיקום של הבאג ב Jira של פלקס, שכן זה באג ידוע (וסגור כבר בגרסה 3, להבנתי), שאם לא מאפסים את השעות, דקות ושניות של אובייקט ה Date, ה DateField פשוט לא מתייחס לזה. פשוט כך.
ניסיתי לחפור פנימה ולראות מה בדיוק קורה שם, אבל נתקלתי בביקורת גבולות עקשנית בדיוק לפני המחלקה: CalendarLayout. אם מישהו מצליח לחפור אליה, שלחו לי פנס ומפה.
זה בעצם העניין. אם אתם רוצים שלוח-השנה יתעדכן, יש לאפס את השעות, דקות ושניות של האובייקט. ולכל מי שאומר "אבל אתה בעצם משנה את ה timestampe של התאריך", אני אשיב: "אתם לגמרי צודקים, פלקס זה כיף".
שמחות.

August 19, 2008

DataGrid.selectedItem לא חבר של sort.

מה קורה?
בלי להאריך יותר מדי, קבלו באג שיכול היה להסיר שיערות מהחזה של אריק זאבי:
יש לכם DataGrid ואתם רוצים שתמיד האיבר הנבחר בו יהיה מסונכרן עם זה שנמצא לכם ב data model, כל שיהיה. בשביל זה אנחנו נשתמש ב Binding, נכון? ודאי. אבל למה אנחנו נחווט אותו? נחווט אותו למאפיין החבוי של ListBase (מאבותיו של DataGrid), הידוע בכיניו SelectedItem. זה נכון ש DataGrid לא נותן לנו אותו אפילו ב code hinting, אבל שועלי קרבות שכמותנו, לא נחפור ונגלה אותו? הרי זה די מתבקש, שיהיה מאפיין שאפשר להגדיר דרכו מי האיבר הנבחר תמיד, לא?
לפלקס יש הסיבות שלו ואני לא תמיד מבין אותן אבל בהחלט מכבד :).
הבעיה מרימה את קודקודה המעוות כאשר אנחנו משתמשים גם ב sort על אותו DataGrid אומלל. שכן אם נחפור עוד יותר בקוד של ListBase נגלה ש SelectedItem לא ממש אוהב לשחק דוקים כשיש sort על ה DataProvider של ה DataGrid. התוצאה היא מחזה מרהיב: בוחרים איבר, ה SelectedIndex נבחר אף הוא (שמתם לב? Index, לא Item), אבל כאשר עושים sort ה selectedItem משתנה אבל ה selectedIndex נשאר כשהיה. מה זה אומר? שבעצם לא השתנתה הבחירה למרות מה שאנחנו רואים... יש יאמרו פאטה-מורגנה, יש יקללו. ואם לא השתנתה הבחירה, אז כל המנגנון שווה לתחת, אם לנסח בעדינות.
אז מה עושים? דבר ראשון, שלא תעיזו להשתמש ב selectedItem כאשר מדובר ב DataGrid. זה לא נכון, זה לא נתמך ואתם תשלמו על זה, האמינו לי.
דבר שני, כל מניפולציה על DataGrid selection צריכה להתבצע דרך ה selectedIndex שלו. איך עושים את זה בדוגמה שהבאתי? הנה דוגמית קטנה....
טוב, רציתי להדביק פה קוד בצורה נורמאלית, אבל בלוגר לא ממש מפרגן - אני אמצא דרך ואחזור אליכם...
מצאתי :), בבקשה:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
creationComplete="initMain();">
<mx:Script>
<![CDATA[
import mx.events.CollectionEvent;
import mx.collections.Sort;
import mx.collections.SortField;
import mx.collections.ArrayCollection;

private var _aItems:ArrayCollection;

[Bindable]
private var selectedItem:Object;

private function initMain():void {
//create data for test
aItems = new ArrayCollection();

for (var i:uint = 1;i <= 10;i++) {
var obj:Object = {sort1:i,sort2:i*-1};
aItems.addItem(obj);
}
selectedItem = aItems.getItemAt(2);
}

private function set aItems(value:ArrayCollection):void {
_aItems = value;
setSelectedItem();
}

[Bindable]
private function get aItems():ArrayCollection {
return _aItems;
}

private function setSelectedItem():void {
if (aItems != null && selectedItem != null) {
for (var i:int = 0; i < this.aItems.length; i++) {
if (aItems.getItemAt(i).sort1 == selectedItem.sort1) {
dgItems.selectedIndex = i;
break;
}
}
}

}

private function refresh():void {
var newDP:ArrayCollection = new ArrayCollection(aItems.source);
newDP.sort = aItems.sort;
newDP.refresh();
aItems = newDP;
}
]]>
</mx:Script>

<mx:DataGrid
id="dgItems"
width="75%"
height="75%"
dataProvider="{aItems}"
updateComplete="setSelectedItem()"
change="selectedItem = dgItems.selectedItem">
<mx:columns>
<mx:DataGridColumn headerText="Sort 1" dataField="sort1"/>
<mx:DataGridColumn headerText="Sort 2" dataField="sort2"/>
</mx:columns>
</mx:DataGrid>

<mx:HBox width="75%">
<mx:Button label="Refresh" click="refresh();"/>
<mx:TextArea
id="output"
text="{dgItems.selectedIndex}"/>
</mx:HBox>

</mx:Application>