PBWOAsso.m


max21 Unternehmensgruppe
#import "Aprica.h"
//	Aprica2
//	copyright Pirmin Braun 1997-2007 - pirmin@pirmin.de
//	all Rights reserved;
@implementation PBWOAsso
ACCESSm(boxId,setBoxId)
ACCESSm(assoID,setAssoID)
ACCESSm(onChange,setOnChange)
ACCESSm(refdTableName,setRefdTableName)
ACCESSm(targetModulName,setTargetModulName)
//dbName soll hier case-Sensitive sein; 
ACCESSm(dbName, setDbName)
ACCESSm(doku,setDoku)
// keine retain-cycles:
- (PBWOEditor *)tvc;
{
    return tvc;
}
- (void)setTvc:(PBWOEditor *)e;
{
    tvc = e;
}
- (void)setGuiName:(NSString *)v;
{
    if(guiName == v)return;
    [guiName release];
    guiName = [v retain];
}
- (BOOL)isAusgeblendet;
{
    return !isCAsso && ([[tvc hiddenFieldNames]ofk:dbName]!=nil);
}
- (int)width;
{ //breite des gesamten controls f. Area
    return width;
}
- (void)setWidth:(int)v;
{
    width=v;
}
- (int)height;
{ //hoehe des gesamten controls f. Area
    return height;
}
- (void)setHeight:(int)v;
{
    height=v;
}
- (int)lines;
{
    int l = height / LINEHEIGHT;
    if(height%LINEHEIGHT > 0.0) l++; //aufrunden
    return l;
}
- (int)editSize;
{
    //size f. input-Element
    // if(isDate)return 13; // 10 + Editierplatz
    return (editWidthPixel - 24) / 6;
}
- (PBDDAttribute *)pba; {return pba;}
- (NSString *)alignment;
{
    return [pba alignment];
}
- (void)resetToOriginal;
{
    [self setPba:pba];
    [self cacheFlags];
}
- (void)setDataTypS:(NSString *)v;
{
// convenience fuer scripting
    if([v iE:SC_DT_CHAR]){dataTyp = DT_CHAR; return;}
    if([v iE:SC_DT_MONEY]){dataTyp = DT_MONEY; return;}
    if([v iE:SC_DT_INT]){dataTyp = DT_INT; return;}
    if([v iE:SC_DT_FLOAT]){dataTyp = DT_FLOAT; return;}
    if([v iE:SC_DT_DATE]){dataTyp = DT_DATE; return;}
    if([v iE:SC_DT_DATETIME]){dataTyp = DT_DATETIME; return;}
    if([v iE:SC_DT_BOOL]){dataTyp = DT_BOOL; return;}
}
- (NSString *)dataTypS;
{
    switch(dataTyp){
        case DT_CHAR: return SC_DT_CHAR;
        case DT_MONEY: return SC_DT_MONEY;
        case DT_INT: return SC_DT_INT;
        case DT_FLOAT: return SC_DT_FLOAT;
        case DT_DATE: return SC_DT_DATE;
        case DT_BOOL: return SC_DT_BOOL;
        case DT_DATETIME: return SC_DT_DATETIME;
    }
    return SC_DT_CHAR;
}
- (BOOL)isPortlet;
{
    return isPortlet;
}
- (void)setPba:(PBDDAttribute *)value;
{
    int i = [_SESSION lang];
    NSString *doku0;
    if(value != pba){
        [pba release];
        pba = [value retain];
    }
//wenn gleich, nur die Werte nochmal uebernehmen
    isButton = ([pba targetTyp]==ATBU);
    isPortlet = ([pba targetTyp]==ATPORTLET);
    [self setDataTyp:[pba dataTyp]];
    [self setDbName:[pba dbName]];	//evt. noch weitere haeufige Variablen redundant halten
    [self cacheFlags]; //vorab, um textArea zu ermitteln
    doku0 = [pba doku0];
    if([doku0 hasSecurePrefix:@"onChange\n"]){
        [self setOnChange:@"document.forms[0].submit();"];
        doku0 = [doku0 substringFromIndex:[@"onChange\n" length]];
    }
    [vl release];
    vl = nil;
    if(i){
        if(!isPortlet){
            [self setGuiName:[pba guiNameForLang:i]];
        }else{
            [self setGuiName:[pba guiName]];
        }
        [self setDoku:[pba dokuForLang:i]];
    }else{
        [self setGuiName:[pba guiName]];
        [self setDoku:[pba doku0]];
    }
    [self setRefdTableName:[pba refdTableName]];
    [self setTargetModulName:[pba targetModulName]];
    nak = [pba nak];
    if(dataTyp == DT_MONEY)nak = 2; //falls bei money nicht gesetzt;
}
- (NSString *)formatOut:(NSString *)s; //bereitet s f. gui auf;
{
    if(!s)s=@"";
    switch(dataTyp){
        case DT_DATE:
        case DT_DATETIME:
            if(!FILLED(s))return EON;
            return [s guiDate];
        case DT_MONEY:
            return MONEYGUI(s);
        case DT_FLOAT:
            return [NSString dottedGuiFromDouble:[s doubleValue] nak:nak];
        case DT_INT:
// Relationen blank wenn 0
            if(isRelation && ![s intValue]){
                return @"";
            }
            return NSS([s intValue]);
    }
    return s;
}
- initWith:(PBWOEditor *)tvcP andAttr:(PBDDAttribute *)attr;
{
    if(![self init])return nil;
    [self setTvc:tvcP];
    [self setAssoID:[tvcP nextAssoID]];
    [[tvcP fassos]addObject:self];
    [self setPba:attr]; //bestimmt u.a. vl
    [self cacheFlags];
    if(isPortlet){
        portletIndex = [tvc portletIndex];
    }
    return self;
}
- (NSString *)portletClassName;
{
// die experssion eines portlet-Attribute enthaelt zeilen, die geparsed werden
// Zeile 1: optionaler ClassName
// Zeile 2: optionaler Event, fuer den sich Portlet registrieren will: registerForClear, registerForRefresh
    if(FILLED([pba expression])){
        NSArray *a = [[pba expression]componentsSeparatedByString:@"\n"];
        NSString *s = [a firstObject];
        if(FILLED(s))return s;
    }
    return [NSSWF @"PBWOPortlet%iA",portletIndex];
}
- (NSString *)registerFor;
{
    if(FILLED([pba expression])){
        NSArray *a = [[pba expression]componentsSeparatedByString:@"\n"];
        if([a count]>1){
            NSString *s = [a oai:1];
            if(FILLED(s))return s;
        }
    }
    return nil;
}
- (BOOL)isMemo;
{
    return isPlainField && [pba length] > 255;
}
- (void)cacheFlags;
{
    isRelation = FILLED(refdTableName);
    hasVL = [pba hasVL];
    isBool = (dataTyp==DT_BOOL);
    isDate = (dataTyp==DT_DATE || dataTyp==DT_DATETIME);
    isMandatory = [pba isMandatory];
    shouldBeBold = [pba isPK]||isMandatory;
    isPlainField = !hasVL && !isBool;
    isTextArea = isPlainField && [pba length] > 255;
    isButton = ([pba targetTyp]==ATBU);
    isPortlet = ([pba targetTyp]==ATPORTLET);
    isProtectedPba = [pba isProtected];
}
- (BOOL)isHTMLCarrier;{return isHTMLCarrier;}
- (void)setIsHTMLCarrier:(BOOL)yn;{isHTMLCarrier=yn;}
- (BOOL)escapeHTML;
{
    return ![pba html];
}
- (BOOL)isMandatory;
{
    return isMandatory;
}
- (void)setIsMandatory:(BOOL)yn;
{
    isMandatory = yn;
}
- (void)dealloc
{
    [val release];
    [refdTableName release];
    [targetModulName release];
    [assoID release];
    [dbName release];
    [guiName release];
    [vlo release];
    [vl release];
    [doku release];
    [pba release];
    [onChange release];
    [super dealloc];
}
- (BOOL)onlyDescr;
{
    return onlyDescr;
}
- (void)setOnlyDescr:(BOOL)yn;
{
    onlyDescr = yn;
}
- (void)setPw:(BOOL)yn;
{
    pw = yn;
}
- (BOOL)pw;
{
    return pw;
}
- (BOOL)isBR;
{
    return isBR;
}
- (void)setIsBR:(BOOL)yn;
{
    isBR = yn;
}
- (BOOL)isImage;
{
    return isImage;
}
- (BOOL)isNI;
{
    return isNI; //namedIcon; Unterart von Image
}
- (NSString *)isImageS;
{
    if(isImage){
        return @"J";
    }else{
        return @"N";
    }
}
- (NSString *)isTextAreaS;
{
    if(isTextArea){
        return @"J";
    }else{
        return @"N";
    }
}
- (void)setIsImage:(BOOL)yn;
{
    isImage=yn;
}
- (void)setIsNI:(BOOL)yn;
{
    isNI=yn;
}
- (BOOL)isButton;
{
    return isButton;
}
- (void)setIsButton:(BOOL)yn;
{
    isButton = yn;
}
- (BOOL)isProtectedPba;
{
    return isProtectedPba;
}
- (void)setIsProtectedPba:(BOOL)yn;
{
    isProtectedPba = yn;
}
//zur pba-unabhaengigen Steuerung
- (BOOL)isProtected;
{
    return isProtected;
}
- (void)setIsProtected:(BOOL)yn;
{
    isProtected = yn;
}
- (NSString *)dbFromGui:(NSString *)s1 resultOK:(BOOL *)resultOK;
{
//zusaetzl. 1000er punkte raus u. evt. komma in punkt
//von asso verwendet, um eingaben in val zu transferieren;
    NSString *ts = @".";
    NSString *s;
    *resultOK = YES;
    if(!s1)s1=EON;
    if(dataTyp == DT_CHAR || dataTyp == DT_BOOL) return s1;
    if(dataTyp == DT_DATE || dataTyp == DT_DATETIME){
        PBDate *pbd;
        if(!FILLED(s1))return EON;
        pbd = [PBDate dateWithFreeString:s1];
        if(!pbd){
            [self markError];
            *resultOK = NO;
            return EON;
        }
        return [[pbd dateAsNSCD]descriptionWithCalendarFormat:ND_FORMAT];
    }
    s = [[s1 componentsSeparatedByString:ts]componentsJoinedByString:EON];
    if([s hasSecurePrefix:@"="]){
        s = [s substringFromIndex:1];
        s = [[s componentsSeparatedByString:@","]componentsJoinedByString:@"."];
        s = [NSSWF @"select %@;",s];
        s = [_APP getSingleValueAsResultFrom:s]; //mysql rechnen lassen
    }else{
        s = [s point];
    }
    if(dataTyp == DT_MONEY)return [NSString dbFromDouble:[s doubleValue] nak:2];
    return [NSString dbFromDouble:[s doubleValue] nak:nak];
}
- (NSString *)guiName;
{
    if([self isAusgeblendet])return EON;
    return guiName;
}
- (BOOL)buttonIsDisabled;
{
    // die Buttons sollen immer gehen, auch bei inaktiven/archivierten und im Anzeigemodus; einzelne Buttons, die nicht gehen sollen, in Event selObjChanged ausschalten;
    if([pba alwaysOn])return NO; // es gibt Buttons, die immer an sein sollen: Uebersichten, System-Buttons
    if([tvc _fieldIsDisabled:dbName])return YES;
    return NO;
}
- (BOOL)inputAllowed;
{
    if(isCAsso || isButton || isImage || onlyDescr || isPortlet || [self isAusgeblendet])return NO;
    if([pba targetTyp]==ATTVCPD)return (!isProtectedPba && !isProtected);
    if([pba targetTyp]==ATTVCSELOBJ && ![tvc selObj])return NO;
    if([pba isAutoPK] || [[pba dbName]iE:@"descri"] || [tvc _fieldIsDisabled:dbName]  || [tvc  anzeigemodus])return NO;
    if([pba isPK]) return ((([tvc  pendingAction]==pa_ins) && !isProtectedPba && !isProtected));
    return ([tvc selObj] && !isProtectedPba && !isProtected);
}
- (NSString *)portletName;
{
    return guiName;
}
- (void)targetToVal;
{
// triggert Datenfluss vom datasource zur Asso
    NSString *s;
    if(isButton || onlyDescr || isPortlet)return;
    if(isImage && !isNI)return; // damit wodVal funktioniert f. title bei namedIcon nur
    switch([pba targetTyp]){
        case ATTVCSELOBJ:
            //der PBWOEditor i.allg.
            [self setVal:[[tvc selObj]vfk:dbName]];
            break;
        case ATTVCPD:
            s = [[tvc parmDict]ofk:dbName];
            if(!s)s=EON;
            [self setVal:s];
            break;
    }
}
- (void)valToTarget;
{
// triggert Datenfluss von Asso zur Datasource
    if(isCAsso)return;
    switch([pba targetTyp]){
        case ATTVCSELOBJ:
            [[tvc selObj] tvfk(val,dbName)];
            break;
        case ATTVCPD:
            if(!val)val=EON;
            [[tvc parmDict]setObject:val forKey:dbName];
            // didValToTarget macht sinn
            break;
    }
    [tvc didValToTargetPba:pba];
}
- (int)descrWidthPixel;
{
    if(noDescr)return 0;
    if(onlyDescr || isTextArea)return width;
    return descrWidthPixel;
}
- (void)determineSizeDwp:(int)dwp ewp:(int)ewp bwp:(int)bwp;
{
// width u. height berechnen; wird benoetigt von singleFieldArea
// bei image erst gar nicht aufrufen
// kann erst erfolgen nachdem einige Flags gesetzt sind; nicht in init... oder setPba..
    if(isImage || isPortlet){
        return;
    }
    descrWidthPixel = dwp;
    editWidthPixel = ewp;
    bezWidthPixel = bwp;
    height = LINEHEIGHT; //default
    if(isBool){
        width = [self descrWidthPixel] + editWidthPixel;
        return;
    }
    if(hasVL){
        width = [self descrWidthPixel] + editWidthPixel;
        return;
    }
    if(isPlainField){
        if(isTextArea){
            width = descrWidthPixel + editWidthPixel + bezWidthPixel;
            height = (([self taRows] + 1) * 16.5) + LINEHEIGHT + 4 + 1;
            return;
        }else{
            width = [self descrWidthPixel] + editWidthPixel;
            height = ([self fieldRows] * LINEHEIGHT);
            if(isRelation){ //den Lookup-Button und Bez. dazurechnen
                width += bezWidthPixel;
            }
            return;
        }
    }
}
- (int)taHeight;
{
    return height - LINEHEIGHT - 1;
}
- (void)setZeilen:(int)value;
{
    zeilen = value;
}
- (int)zeilen;
{
    return zeilen;
}
- (int)taCols;
{
    return width / 9;
}
- (int)taRows;
{
// fuer textareas
    if(zeilen > 0)return zeilen; //abw. zeilen per lif
    return 8;
}
- (int)fieldRows;
{
// fuer alle anderen Oberflaechenelemente
    if(zeilen > 0)return zeilen; //abw. zeilen per lif
    return 1;
}
- (int)dataTyp;{return dataTyp;}
- (void)setDataTyp:(int)value;{dataTyp = value;}
- (int)classNo;{return classNo;}
- (void)setClassNo:(int)value;{classNo = value;}
- (int)nak;{return nak;}
- (void)setNak:(int)value;{nak = value;}
- init;
{
    if(!(self = [super init]))return nil;
    tvc = nil;
    dataTyp = DT_CHAR;
    isProtected = NO;
    hasError = NO;
    noDescr = NO;
    isCAsso = NO;
    onlyDescr = NO; //f. reine CustomText-Felder
    isImage = NO; //f. reines bildchen anzeigen
    isButton = NO;
    isPortlet = NO;
    isHTMLCarrier = NO;
    isNI = NO; //NamedIcon
    [self setBez:EON];
    width=0; height=0; zeilen=0;
    return self;
}
- (void)setBez:(NSString *)v;
{
    if([v iE:bez])return;
    [bez release];
    bez = [v retain];
}
- (void)setNoDescr:(BOOL)value;
{
    noDescr = value;
}
- (BOOL)noDescr;
{
    return noDescr;
}
- (NSString *)heightS;
{
    return NSS(height);
}
- (NSString *)widthS;
{
    return NSS(width);
}
- (BOOL)isChecked;
{
    if(!isBool)return NO;
    return [val iE:SC_BOOL_TRUE];
}
- (void)setIsChecked:(BOOL)yn;
{
    NSString *s;
    if(!isBool)return;
    if(yn){
        s = SC_BOOL_TRUE;
    }else{
        s = SC_BOOL_FALSE;
    }
    if(![val iE:s]){
        [self setValFromWod:s];
    }
}
- (BOOL)isRelation;
{
    return isRelation;
}
- (BOOL)hasVL;
{
    return hasVL;
}
- (BOOL)isBool;
{
    return isBool; 
}
- (BOOL)isDate;
{
    return isDate;
}
- (BOOL)shouldBeBold;
{
    return shouldBeBold;
}
- (BOOL)isPlainField;
{
    return isPlainField;
}
- (BOOL)isTextArea;
{
    return isTextArea;
}
- (NSString *)bez;
{
// bez nicht mehr in App cachen, sondern hier
    if([self isAusgeblendet] || !FILLED(val)){
        [self setBez:EON];
        return bez;
    }
    if(FILLED(bez))return bez; // gecachten wert behalten
    if(isRelation){ //lazy ermitteln; nicht alle assos muessen ihre bez anzeigen
	// nicht die bez des foreign EO holen, sondern selbst die werte der descri-Felder beschaffen
        [self setBez:[_APP descriForEn:refdTableName pk:val]];
    }
    return bez;
}
- (BOOL)isCAsso;
{
    return isCAsso;
}
- (void)setIsCAsso:(BOOL)yn;
{
    isCAsso = yn;
}
- (NSString *)bezeichnungForValue:(NSString *)s;
{
    if(!FILLED(s))return EON;
    if(![self vl])return s;
    {
        int i,j;
        for(i=0,j=[[self vl] count];i<j;i++){
            PBVLO *pbvlo = [[self vl] oai:i];
            if([[pbvlo value]iE:s]){
                return [pbvlo bez]; // in richtiger Sprache
            }
        }
    }
    return EON;
}
- (NSString *)wodVal;
{
// wenn man nil im response uebergibt, gilt das Feld als nicht geaendert, wenn es leer bleibt
// sonst wuerde es im takeValuesFromRequest versorgt werden
// ermittelt seinen Wert selbst bei Bedarf
    if((![tvc selObj] && [pba targetTyp]==ATTVCSELOBJ && !(isCAsso)))return nil;
    if(!FILLED(val))return nil;
    if(isNI)return val;
    if(hasVL)return [pba bezeichnungForValue:val];
    return [self formatOut:val];
}
- (void)setWodVal:(NSString *)s;
{
// wird von WO aufgerufen
    NSString *dbVal1;
    BOOL resultOK=NO;
    if(![self inputAllowed])return; //es werden sehr wohl werte zurueckgeschickt! z.B. bei einer Textarea, die eigentlich gesperrt ist;
// wenn gar nicht in den formvalues enthalten, auch nix machen
    if(![[[[_SESSION context]request] vfk:@"_formValues"]ofk:dbName])return;
    if((dataTyp == DT_DATE || dataTyp == DT_DATETIME || isRelation) && ([s hasSecureSuffix:@"."] || [s hasSecureSuffix:@"*"])){
// Kalender bzw. Lookup zum Nachschlagen aufrufen
        s = [s stringWithoutLastChar];
        if(isRelation){
// foreign key nachschlagen;
            PBWOLookup *pbe;
// mit generischem Lookup-Modul
            PBSQLQualifier *cmq;
            NSDictionary *rd;
            NSString *soas;
            pbe = (PBWOLookup *)MODUL(@"PBWOLookup");
            if(!pbe){
                LOGI(TRANSLATION(@"Modul PBWOLookup nicht bekommen"));
                return;
            }
            [pbe setCallingModul:tvc]; //cleared auch callingMQ und uebernMode
            [tvc setWaitingForName:self];
            [pbe setNewCMQName:[tvc cmqName]];
            [pbe setMyTable:[MYDD tableNamed:refdTableName]]; // loest neuzeichnen aus; dafuer muss waitingForName bereits gesetzt sein
            [pbe setSuchFelderQ:nil];
//cmq per script ermitteln
            [[tvc parmDict] setObject:refdTableName forKey:@"p_entityname"];
            [[tvc parmDict] setObject:dbName forKey:@"p_dbName"];
            [[tvc parmDict] setObject:[tvc cmqName] forKey:@"p_cmqName"];
            rd = [_APP executeScriptNamed:@"getCMQForAssoFind" datasource:tvc parmDict:[tvc parmDict]];
            if([[rd ofk:@"scriptRC"]iE:@"N"])return;
            soas = [rd ofk:@"rp_soa"];   // sortOrderArray
            if(FILLED(soas)){
                [pbe setSoseq:soas];
            }
            cmq = [rd ofk:@"rp_cmq"];
            [[pbe ma]removeAllObjects];
// Eingabe in currentAso interpretieren:
            if(dataTyp == DT_INT && ([s iE:@"0"])){
                s = @"";
            }
            [_SESSION clearErrors]; // unnoetige Meldung "artikelnr falsch..."
            [pbe setCallingMQ:cmq];
            [pbe setCombiSuchContent:s];
            [pbe combiSucheActed];
            if([[pbe ma]count]==1){
                // genau 1 gefunden, direkt nehmen
                [tvc takeString:[[[pbe ma]firstObject]primaryKey]];
                [tvc executeDidTakeValuesFromRequest];
                [pbe setCallingModul:nil]; //cleared auch callingMQ
                return;
            }
            // sonst Trefferliste aufblenden
            [tvc bringToFront:pbe];
            return;
        }else{
            PBWOEditor	*e = MODUL(@"akte");
            if(e){
                [[e parmDict]setObject:[_APP today] forKey:@"startingDate"];
                if(FILLED(s)){
                    dbVal1 = [self dbFromGui:s resultOK:&resultOK];
                    if(resultOK){
                        [[e parmDict]setObject:dbVal1 forKey:@"startingDate"];
                    }
                }
                [[e parmDict]setObject:@"J" forKey:@"uebernehmen"];
                [_APP kalender:e];
                [e setSelectedBoxName:@"Kalender"]; // besser man aendert den Registertitel nicht...
                [e minimize];
                [tvc setWaitingForName:self];
                [e setCallingModul:tvc]; // cleared auch callingMQ
                [tvc bringToFront:e];
            }else{
                LOGI(TRANSLATION(@"keine Berechtigung."));
            }
        }
        return;
    }
    if([self isTextArea]){
        dbVal1 = [s stringWithoutTextareaCR];
        if([dbVal1 rangeOfString:@"$$t"].length){
            dbVal1 = [dbVal1 replace:@"$$t" with:[[NSCalendarDate date]descriptionWithCalendarFormat:ND_GUIDT_FORMAT]];
        }
    }else{
        dbVal1 = [self dbFromGui:s resultOK:&resultOK];
        if(!resultOK)return;
    }
    if(!FILLED(val) && !FILLED(dbVal1))return;
    if([val iE:dbVal1])return;
    [self setValFromWod:dbVal1];
}
- (void)setValFromWod:(NSString *)v;
{
    [val release];
    val = [v retain];
    [self setBez:EON]; //cleared bez-cache; descri einer Relation;
    [self valToTarget];
}
- (void)setVal:(NSString *)v;
{
// von datasource aus
    if(v==val)return;
    if([v iE:val])return;
    if(dataTyp == DT_MONEY || dataTyp == DT_INT ||  dataTyp == DT_FLOAT){
        if([v doubleValue] == [val doubleValue])return;
    }
    if(isTextArea){
        v = [v stringWithoutTextareaCR];
        if([v iE:val])return;
    }else{
        if((dataTyp == DT_CHAR) && [v rangeOfString:@"\n"].length){
            v = [[v replace:@"\n" with:@" "] replace:@"\r" with:@" "];
        }
    }
    [val release];
    val = [v retain];
    [self setBez:EON]; // cleared bez-cache; descri einer Relation;
    if(hasVL){
// neues vlo setzen
        int i,j;
        for(i=0,j=[[self vl]count];i<j;i++){
            PBVLO *pbvlo = [[self vl]oai:i];
            if([[pbvlo value]iE:val]){
                [self setSelectedPBVLO:pbvlo];
                return;
            }
        }
        [self setSelectedPBVLO:[vl firstObject]];
    }
}
- (NSString *)val;
{
    return val;
}
- (PBVLO *)selectedPBVLO;
{
    return vlo;
}
- (void)setVlVal:(NSString *)s;
{
    if(![self inputAllowed])return;
    if(!FILLED(s)){
        s = (NSString *)EON;
    }
    if(![val iE:s]){
        [self setValFromWod:s];
    }
}
- (void)setSelectedPBVLO:(PBVLO *)o;
{
    if([vlo iE:o])return;
    [vlo release];
    vlo = [o retain];
    [self setVlVal:[vlo value]];
}
- (NSMutableArray *)_vl;
{
// um in Script zu manipulieren
    if(!vl){
        MA(vl);
        [vl addObjectsFromArray:[pba vl]];
    }
    return vl;
}
- (NSArray *)vl;
{
    if(vl)return vl; // dynamische haben eigene VL;
    return [pba vl];
}
- (NSString *)vlVal;
{
    if([self isAusgeblendet])return EON;
    return val;
}
- (void)markError;
{
    hasError = YES;
    [[tvc errorAssos]addObjectUniq:self];
}
- (NSString *)descrAreaClass;
{
    if(hasError)return @"descrAreaErr";
    if(classNo)return [NSSWF @"descrArea%i",classNo];
    if(shouldBeBold)return [NSSWF @"descrAreaBold",classNo];
    return @"descrArea";
}
- (void)resetError;
{
    hasError = NO;
}
- (NSString *)title;
{
    if([self isAusgeblendet])return EON;
    return [self guiName];
}
- (NSString *)nameNachschlagen;
{
    return [NSSWF @"%@_nachschlagen",dbName];
}
- (NSString *)nameGotoLink;
{
    return [NSSWF @"%@_GotoLink",dbName];
}
@end
Foto