PBWOEditor.m


max21 Unternehmensgruppe
#import "Aprica.h"
//	Aprica2
//	copyright Pirmin Braun 1997-2007 - pirmin@pirmin.de
//	all Rights reserved;
@implementation PBWOEditor
ACCESSClassm(soa, setSoa, NSArray)
ACCESSClassm(templ, setTempl, WOElement)
ACCESSm(selectedBoxName,setSelectedBoxName);
ACCESSClassm(waitingForName,setWaitingForName,PBWOAsso);
ACCESSClassm(currentAction, setCurrentAction, PBActionO)
ACCESSm(guiName,setGuiName);
ACCESSClassm(commonBox,setCommonBox,NSArray);
ACCESSClassm(suchabfrButtons,setSuchabfrButtons,NSArray);
ACCESSm(nameForScript,setNameForScript)
- (NSMutableArray *)clearOnSelObjChanged;{return clearOnSelObjChanged;}
- (NSMutableArray *)refreshOnSelObjChanged;{return refreshOnSelObjChanged;}
- (NSMutableDictionary *)portletDict;{return portletDict;}
- (NSMutableArray *)stateArray;{return stateArray;}
- (NSMutableDictionary *)colWidthDict;
{
    return colWidthDict;
}
- (NSMutableDictionary *)changedInRequest;
{
    return changedInRequest;
}
- (NSMutableDictionary *)parmDict;
{
    return parmDict;
}
- (NSMutableArray *)boxNameArray;
{
    return boxNameArray;
}
- (NSMutableArray *)filterQs;
{
    return filterQs;
}
- (BOOL)hasFilter;
{
    return ([filterQs count] > 0);
}
- (int)portletIndex;{return portletIndex;}
- (NSString *)nextAssoID;
{
    return [NSSWF @"asso_%i",assoIDCounter++];
}
- (WOElement *)invokeActionForRequest:(WORequest*)aRequest inContext:(WOContext*)aContext
{
//take Values ist hier gelaufen
    WOElement *e = nil;
    NS_DURING;
    e = [super invokeActionForRequest:aRequest inContext:aContext]; // hier wird df oder eine explizite action aufgerufen
    NS_HANDLER;
    NS_ENDHANDLER;
    [parmDict setSecureObject:selObj forKey:@"p_eo"];
    [_APP executeScriptNamed:[NSSWF @"%@/didInvokeActionForRequest",nameForScript] datasource:self parmDict:parmDict];
    [parmDict removeObjectForKey:@"p_eo"];
    if([self nextModul]){
        [_SESSION setNextModul:nextModul];
        return nextModul; //hat Vorrang;
    }
    if(e){
        [_SESSION setNextModul:(PBWOEditor *)e];
        return e; //actions, die explizit seite zurueckgeben
    }
    [_SESSION setNextModul:self];
    return self;  //falls eine instanceForBundleNamed nicht gefunden wird
}
- (NSString *)layoutInfoPathForRead;
{
    NSString *s;
    NSString *userName = [_SESSION use_lif_from];
    if(!userName)userName = CURRENTUSER;
    s = [NSSWF @"%@/LayoutsUsers/%@/%@.lif",MANDANTPATH,userName,[self name]];
    if([myFM fileExistsAtPath:s])return s;
    return [NSSWF @"%@/LayoutsUsers/Administrator/%@.lif",MANDANTPATH,[self name]];
}
- (BOOL)badLif;
{
    return badLif;
}
- (NSString *)nameForLifdictKey:(NSString *)k;
{
    NSString *label,*s;
    NSArray *a1;
    a1 = [k componentsSeparatedByString:@"|"];
    s = [a1 firstObject];
    if([a1 count]==3 && ([s iE:@"p"] || [s iE:@"a"] || [s iE:@"P"] || [s iE:@"A"])){
        label = [a1 lastObject];
    }else{
        label = k;
    }
    return label;
}
- (NSMutableArray *)fassos;
{
    return fassos;
}
- (PBWOAsso *)currentAsso;
{
    return currentAsso;
}
- (NSString *)cmqName;
{
    return [NSSWF @"%@_%@_%@",[waitingForName refdTableName],[self name],[waitingForName dbName]];
}
- (void)oeffneUebersicht:(NSString *)ueName tableName:(NSString *)tableName;
{
    [self oeffneUebersicht:ueName tableName:tableName ueb_mode:UEB_NONE];
}
- (void)oeffneUebersichtMS:(NSString *)ueName tableName:(NSString *)tableName;
{
    [self oeffneUebersicht:ueName tableName:tableName ueb_mode:UEB_MULTI_DEL];
}
- (void)oeffneUebersichtMSRef:(NSString *)ueName tableName:(NSString *)tableName;
{
    [self oeffneUebersicht:ueName tableName:tableName ueb_mode:UEB_MULTI_REF];
}
- (void)oeffneUebersicht:(NSString *)ueName tableName:(NSString *)tableName ueb_mode:(int)ueb_mode;
{
// UEB_NONE = kein Uebernehmenmode; bei Click zum default-Editor springen;
// UEB_SINGLE = nur 1 anklickbar; f. Kalender;
// UEB_MULTI_DEL = Multi-Select; uebernommene werden aus Tableview geloescht;
// UEB_MULTI_REF = Multi-Select Refetch; nach uebernehmen wird neu gefetched;
// wird i.a. von Buttons aufgerufen: expression:
// invk %datasource,oeffneUebersicht:tableName:,$ueName,$tn
    PBWOUebersicht *pbe;
    PBDDTable *t = [MYDD tableNamed:tableName];
    PBSQLQualifier *cmq;
    NSString *s,*soas;
    NSDictionary *rd;
    if(!t)return;
    pbe = MODUL(@"PBWOUebersicht");
    
    if(!pbe){
        LOGI(TRANSLATION(@"Modul PBWOUebersicht nicht bekommen"));
        return;
    }
    [pbe setSuchFelderQ:nil];
    [[pbe filterQs] removeAllObjects];
    if(![pbe configureUebersicht:ueName table:t cm:self])return;
//cmq per script ermitteln
// p_tableName Zieltablle, in der nachgeschlagen werden soll
// p_ueName Name der Uebersicht
// p_cmn modulname
// p_lifFileName  modulname, ueName; wie lifFileName in PBWOUebersicht
// rp_cmq Rueckgabeparameter: erzeugter callingModulQualifier
// rp_csc Returnparameter Combisuch-Content; wird ins combisuchfeld eingetragen und damit gesucht; zieht staerker als rp_cmq
// rp_soa Returnparameter sort order array; String im soaFrom-Format steuert Sortierung
// parmDict nicht leeren, weil ja vielleicht der Button noch weitere Parameter eingestellt hat
    [parmDict setObject:tableName forKey:@"p_tableName"];
    [parmDict setObject:ueName forKey:@"p_ueName"];
    [parmDict setObject:[self name] forKey:@"p_cmn"];
    [parmDict setObject:[NSSWF @"%@_%@",[self name],ueName] forKey:@"p_lifFileName"];
    rd = [_APP executeScriptNamed:@"getCMQForUebersicht" datasource:self parmDict:parmDict];
    if([[rd ofk:@"scriptRC"]iE:@"N"])return;  // abbruch
    cmq = [rd ofk:@"rp_cmq"]; // callingModulQualifier
    s = [rd ofk:@"rp_csc"];   // combiSuchContent
    soas = [rd ofk:@"rp_soa"];   // sortOrderArray
    [pbe setUebernMode:ueb_mode];
    if(FILLED(soas)){
        [pbe setSoseq:soas];
    }
    if(s){
	// combiSuchContent uebergeben; hat Vorrang
        [pbe setCombiSuchContent:s];
        [pbe combiSucheActed];
    }else{
        [[pbe ma]removeAllObjects];
        [pbe executeCallingMQ:cmq];
    }
    [self bringToFront:pbe];
}
- (void)followLink;
{
    PBWOEditor	*pbe;
    PBSQLQualifier *q;
    NSString *pkn,*en=[currentAsso refdTableName],*s=[currentAsso val];
    NSString *targetModulName;
    if(!FILLED(s))return;
    pkn = [[MYDD tableNamedCheap:en]primaryKeyName];
    if(!pkn)return;
    q = [PBSQLQualifier qualifierWithString:[NSSWF @"%@ = '%@'",pkn,s]];
    targetModulName = [currentAsso targetModulName]; //an attribut hinterlegt evt.
    if(FILLED(targetModulName)){
        pbe = MODUL(targetModulName);
        if(!pbe)return; //wenn targetmodul angegeben, muss dieses genommen werden
    }else{
        pbe = [_SESSION instanceForBundleNamed:en];
    }
    SUCH_EXTERNAL(pbe,q);
}
- (void)filterAttrNames:(NSMutableArray *)lifa pa:(NSMutableArray *)pa;
{
// aus den Strings im lifa, die attributnamen sind, attribute machen; die steueranweisungen belassen; unbekanntes rausfiltern;
// was nicht in allAttr ist, raus
// Attribute und Formatanweisungen in pa sammeln
// Formatanweisungen als NSString;
// unsichtbare Felder und Felder nur fuer Root rausfiltern
    int i,j;
    NSString *s;
    PBDDAttribute *pba;
    [pa removeAllObjects];
    for(i=0,j=[lifa count];i<j;i++){
        s = [lifa oai:i];
        if([s hasSecurePrefix:@"<"]){
            [pa addObject:s]; //Formatanweisung
            continue;
        }
        if((pba = [allAttr ofk:s])){
            if(![pba isVisible]){
                [pa addObject:@"<invisible>"]; //Formatanweisung; cleared feldbezogene flags, damit diese nicht auf naechstes uebergehen;
                continue;
            }
            [pa addObject:pba]; //echtes Attribut
        }
    }
}
- (BOOL)mayNotLeaveConfig;
{
    return ![self mayLeaveConfig];
}
- (BOOL)mayNotChangeSelectedObject;
{
    return ![self paNon];
}
- (void)createFullyQualifiedLif;
{
}
- (void)saveLif:(NSMutableDictionary *)dict path:(NSString *)path;
{
    LMD;
    NSArray *a = [dict allKeys];
    int i,j;
    [myFM createAllDirsAtPath:[path stringByDeletingLastPathComponent]];
    for(i=0,j=[a count];i<j;i++){
        NSString *k = [a oai:i];
        if(![k hasSecureSuffix:@"|System"])[lmd setObject:[dict ofk:k] forKey:k];
    }
    [[self lifStringWithDict:lmd] WTF:path];
}
- (void)saveLif;
{
    if(!myTable)return;
    if(![_SESSION use_lif_from]){
        [self saveLif:lifDict path:[NSSWF @"%@/LayoutsUsers/%@/%@.lif",MANDANTPATH,CURRENTUSER,[self name]]];
    }
}
- (void)useLif:(NSString *)c path:(NSString *)s dict:(NSMutableDictionary *)dict;
{
// den String c in lifdict dict umformen
// path:s ist nur fuer log-meldungen
    NSMutableArray *lma;
    NSString *k;
    int i,n;
    NSArray *ws,*ls = [c componentsSeparatedByString:@"\n"];
    NSString *fld,*l;
    n = [ls count];
    for (i=0;i<n;i++) {
        l = [[ls oai: i] stringWithoutWindowsShit];
        ws = [l componentsSeparatedByString:@"\t"];
        if ([ws count]!=2) {
//		    LOGS(([NSSWF @"Lif fehlerhaft: %@ - '%@'",s,l]));
            continue;
        }
        k = [ws oai: 0];
        fld = [ws oai: 1];
        if([k iE:SC_LIF_Unres] || [k iE:SC_LIF_Unknown]) continue;
        if ([k iE: @"soseq"])continue; // nicht mehr im LIF, sondern im ueo.soseq
        if ([fld iE: @"-"]) {
// nervt if ([dict ofk:k]) LOGS(([NSSWF @"Warning: replacing %@ in %@",k,s]));
            lma = [NSMutableArray arrayWithCapacity:10];
            [dict setSecureObject:lma forKey:k];
        } else {
            lma = [dict ofk: k];
            if([fld hasSecurePrefix: @"<"]){
                [lma addObject: fld];
            }else{
                NSArray *a1 = [fld componentsSeparatedByString:@":"];
                if([a1 count]>1){
                    if(![allAttr ofk: [a1 firstObject]])continue;
                }else{
                    if(![allAttr ofk:fld])continue;
                }
                [lma addObject: fld];
            }
        }
    }
}
- (void)loadLif:(NSString *)s;
{
    NSString *c;
//feste keys (obsolete):
//unresolved  	= nicht untergebrachte attr.
//unknown	= ehemals in lif, aber nicht in allAttr gefunden
    [lifDict removeAllObjects];
    if(!myTable)return;
    if([myFM fileExistsAtPath:s]){
        NS_DURING;
	c = [NSSWCOF s];
        [self useLif:c path:s dict:lifDict];
        [self addScriptTab];
        NS_HANDLER;
        LOGS_Ex(([NSSWF @"Lif in %@ fehlerhaft;",s]));
        badLif = YES;
        NS_ENDHANDLER;
    }
    if(![lifDict count]){
        [self createDefaultLayout];
//wenn bundle kein lif hatte aufgrund parsing problem, das generierte default-lif nicht schreiben
//ansonsten in std-directory schreiben, nicht in kunden-spez., da erstmaliges speichern
        if(!badLif && [lifDict count])[self saveLif];
    }
    if(![lifDict ofk:SC_LIF_COMMON])[lifDict setObject:[NSMutableArray array] forKey:SC_LIF_COMMON];
    if(![lifDict ofk:SC_LIF_SUCHABFR])[lifDict setObject:[NSMutableArray array] forKey:SC_LIF_SUCHABFR];
    [lifDict removeObjectForKey:SC_LIF_DRUCK];
    [lifDict removeObjectForKey:SC_LIF_EXPORT];
    [lifDict removeObjectForKey:@"_uebersicht"];
    [lifDict removeObjectForKey:@"_funktionen"];
}
- (void)loadLif;
{
    [self loadLif:[self layoutInfoPathForRead]];
}
- (NSString *)soseq;
{
    return soseq;
}
- (void)setSoseq:(NSString *)s;
{
    int i,j;
    LMDN(colByName);
    NSArray *a;
    PBWOTVCCol *column;
    LMAN(soa_elements);
    if(s==soseq)return;
// Spalten zuruecksetzen
    [self setTvcSortCol:nil];
    for(i=0,j=[columns count];i<j;i++){
        column = [columns oai:i];
        [column setTvNewSortMode:SORTMODE_N];
        [colByName setObject:column forKey:[column dbName]];
    }
// alte Syntax aus Lif auf neue konvertieren
    if(FILLED(s)){
        if([s hasSecurePrefix:@"-"]){
            s = [[s secureSubstringFromIndex:1]stringByAppendingString:@":d"];
        }else if([s hasSecurePrefix:@"+"]){
            s = [s secureSubstringFromIndex:1];
        }
    }
// pruefen, ob noch alle Sortierspalten vorhanden und in DB und Sortierspalten visualisieren
    a = [s componentsSeparatedByString:@","];
    for(i=0,j=[a count];i<j;i++){
        NSString *s = [a oai:i];
        int sortmode;
        PBDDAttribute *pbat;
        if([s hasSecureSuffix:@":d"]){
            s = [s stringWithoutSuffix:@":d"];
            sortmode = SORTMODE_D;
        }else{
            sortmode = SORTMODE_A;
        }
        pbat = [myTable plainAttrNamed:s];
        if(pbat && [pbat isDB]){
            if(sortmode == SORTMODE_A){
                [soa_elements addObject:s];
            }else{
                [soa_elements addObject:[NSSWF @"%@:d",s]];
            }
            column = [colByName ofk:s];
            if(column)[column setTvNewSortMode:sortmode];
            if(column && !tvcSortCol)[self setTvcSortCol:column]; // erste spalte f. Positionieren
        }
    }
    [soseq release];
    soseq = [[soa_elements componentsJoinedByString:@","] retain];
    [self setSoa:[NSArray soaADFrom:soseq]];
}
- (void)saveSoseq;
{
// von von QueryPortlet oder Spaltenklick gesetzt wurde
    NSString *s = soseq;
    if(!s)s = @"";
    [[_SESSION moduleSoseq] setObject:s forKey:[self name]];
    [_SESSION saveSoseq];
}
- (void)addCustomTab;
{
    NSString *tabName = @"a|600|Custom";
    [lifDict setSecureObject:[NSMutableArray array] forKey:tabName];
}
- (void)addScriptTab;
{
// bestehendes vorher loeschen
    NSString *tabName = @"a|900|System";
    NSArray *ks = [lifDict allKeys];
    int i,j;
    LMAN(fields); // muss mutable sein f. Editieren
    NSArray *a = [_APP systemtab];
    [fields addObjectsFromArray:a];
    for(i=0,j=[ks count];i<j;i++){
        NSString *k = [ks oai:i];
        if([k hasSecureSuffix:@"|System"]){
            [lifDict removeObjectForKey:k];
        }
        if([k hasSecureSuffix:@"|Media"]){
            [lifDict removeObjectForKey:k];
        }
        if([k hasSecureSuffix:@"|Zuord"]){
            [lifDict removeObjectForKey:k];
        }
    }
    if(IS_ROOT || ![[[_APP configDict]ofk:@"no_system_tab"]iE:@"J"]){
    // System-Tab kann abgeschaltet werden
        [lifDict setSecureObject:fields forKey:tabName];
    }
}
- (void)mapVisibleTVAttrToLifDict;
{
    NSArray *a = [self visibleTVAttr];
    int i,j;
    LMA;
    for(i=0,j=[a count];i<j;i++){
        PBDDAttribute *pba =[a oai:i];
        int customWidth = [[colWidthDict ofk:[pba dbName]]intValue];
        if(customWidth){
            [lma addObject:[NSSWF @"%@:%i",[pba dbName],customWidth]];
        }else{
            [lma addObject:[pba dbName]];
        }
    }
    if([lma count])[lifDict setSecureObject:lma forKey:SC_LIF_TV];
}
- (WOElement *)previewConfig;
{
    if(configMode==CONFIGMODE_Lif){
// momentanes aktivieren
        [self useLif:lifEditArea path:@"(edit-area)" dict:lifDict];
        [self addScriptTab];
    }else{
        [self mapVisibleTVAttrToLifDict];
    }
    [self redrawAfterLeaveConfig];
    return self;
}
- (WOElement *)leaveConfig;
{
    NSString *oldBoxName;
    if(configMode==CONFIGMODE_Lif){
        [self saveAsMyLif]; //lifeditarea speichern als lif
        [self loadLif]; //gespeichertes laden
    }else{
        [self mapVisibleTVAttrToLifDict];
    }
    isConfigMode=NO;
    [self redrawAfterLeaveConfig];
    if(configMode!=CONFIGMODE_Lif){
        [self saveLif];
    }
    
// versuchen, wieder auf alte Box zu positionieren
    oldBoxName = [parmDict ofk:@"selectedBoxName"];
    if(FILLED(oldBoxName)){
        int i = [boxNameArray indexOfObject:oldBoxName];
        if(NSNotFound == i)return self;
        if([selectedBoxName iE:oldBoxName])return self;
        [self setSelectedBoxName:oldBoxName];
    }
    return self;
}
- (WOElement *)abortConfig;
{
    isConfigMode=NO;
    [self loadLif]; //urspruengliches wieder laden, editierungen verwerfen;
    return self;
}
- (void)redrawAfterLeaveConfigAction;
{
// neu zeichnen Button
    [self loadLif]; //File kann extern bearbeitet worden sein
    [self redrawAfterLeaveConfig];
}
//lif-Editor
ACCESSClassm(selectedFields,setSelectedFields,NSArray);
ACCESSClassm(selectedFieldsOrControls,setSelectedFieldsOrControls,NSArray);
ACCESSClassm(fieldsInSelectedRegister,setFieldsInSelectedRegister,NSMutableArray);
ACCESSClassm(currentFieldInSelectedRegister, setCurrentFieldInSelectedRegister,PBStringWrapper)
ACCESSm(currentRegister, setCurrentRegister)
ACCESSm(selectedRegister, setSelectedRegister)
ACCESSm(selectedRegisterModify, setSelectedRegisterModify)
ACCESSm(newRegisterName, setNewRegisterName)
ACCESSm(currentFieldItem, setCurrentFieldItem)
ACCESSm(fieldTargetPos, setFieldTargetPos)
ACCESSm(selectedField, setSelectedField)
- (NSArray *)registers;
{
    LMA;
    int i,j;
    NSArray *a = [lifDict allKeys];
    for(i=0,j=[a count];i<j;i++){
        NSString *s = [a oai:i];
        if([s iE:SC_LIF_Unknown] || [s iE:SC_LIF_Unres] || [s iE:SC_LIF_TV] || [s iE:@"soseq"])continue;
        if([s hasSecureSuffix:@"|System"])continue;
        [lma addObject:s];
    }
    return [lma sortedArrayUsingSelector:@selector(compareBySecondIntField:)];
}
- (BOOL)isCurrentModule;
{
// in launched Moduls
    return (currentLaunchedModule == self);
}
- (BOOL)isFixRegister;
{
    return [currentRegister iE:SC_LIF_COMMON]  || [currentRegister iE:SC_LIF_SUCHABFR];
}
- (BOOL)isSelectedRegister;
{
    return currentRegister == selectedRegister;
}
- (WOElement *)deleteSelectedRegister;
{
    int i = [[self registers] indexOfObject:selectedRegister];
    int j;
    [lifDict removeObjectForKey:selectedRegister];
    j = [[self registers] count];
    if(i>=j)i=j-1;
    [self setSelectedRegister:[[self registers]oai:i]];
    [self setSelectedRegisterModify:selectedRegister];
    [self rebuildFieldsInSelectedRegister];
    return self;
}
- (WOElement *)gotoCurrentRegister;
{
    [self setSelectedRegister:currentRegister];
    [self setSelectedRegisterModify:selectedRegister];
    [self rebuildFieldsInSelectedRegister];
    return self;
}
- (WOElement *)createNewRegister;
{
    if(!FILLED(newRegisterName)){
        LOGI(TRANSLATION(@"bitte Name fuer neues Register angeben"));
        return self;
    }
    if([lifDict ofk:newRegisterName]){
        LOGI(TRANSLATION(@"dieses Register gibt es schon; bitte anderen Namen waehlen;"));
        return self;
    }
    if([[newRegisterName componentsSeparatedByString:@"|"]count] != 3){
        LOGI(TRANSLATION(@"falsches Format fuer Registername; Bsp.:\"a|200|Name\""));
        return self;
    }
    [lifDict setSecureObject:[NSMutableArray array] forKey:newRegisterName];
    return self;
}
- (void)rebuildFieldsInSelectedRegister;
{
    LMA;
    int i,j;
    NSArray *a =[lifDict objectForKey:selectedRegister];
//stringWrapper, damit auch gleiche strings unterschieden werden, z.B. mehrfache <br>
    for(i=0,j=[a count];i<j;i++){
        [lma addObject:[PBStringWrapper stringWrapperWithString:[a oai:i]]];
    }
    [lma addObject:[PBStringWrapper stringWrapperWithString:@"<Ende>"]];
    [self setFieldsInSelectedRegister:lma];
}
- (BOOL)isInLifDict:(NSString *)dbName;
{
    if(![lifFieldDict count]){ //wird regelmaessig geleert
        NSArray *a = [lifDict allKeys];
        int i,j;
        for(i=0,j=[a count];i<j;i++){
            NSString *k = [a oai:i];
            NSArray *a1;
            if([k iE:SC_LIF_TV])continue;
            if([k iE:SC_LIF_SUCHABFR])continue;
            if([k iE:SC_LIF_Unres])continue;
            if([k iE:SC_LIF_Unknown])continue;
            a1 = [lifDict ofk:k];
            if(![a1 isKindOfClass:[NSArray class]])continue; // es sind auch strings drin;
            [lifFieldDict setObjects:a1 forKeys:a1];
        }
    }
    return ([lifFieldDict ofk:dbName]!=nil);
}
- (void)rebuildFieldsOrControl;
{
    NSArray *a = [allAttr allValues];
    int i,j;
    LMA;
    [fieldsOrControls removeAllObjects];
    if(fieldsOrControlsTags)[fieldsOrControls addObjectsFromArray:[[self controlFields] sortedArray]]; //strings
    for(i=0,j=[a count];i<j;i++){
        PBDDAttribute *pba = [a oai:i];
        NSString *dbName = [pba dbName];
// filter: fieldsOrControlsButtons,fieldsOrControlsFields,fieldsOrControlsParms,fieldsOrControlsUsed,fieldsOrControlsUnused,fieldsOrControlsFilled
        if([self isInLifDict:dbName]){
            if(!fieldsOrControlsUsed)continue;
        }else{
            if(!fieldsOrControlsUnused)continue;
        }
        if(fieldsOrControlsFilled && [self selObj] && [pba targetTyp]==ATTVCSELOBJ){
            NSString *s = [[self selObj] vfk:[pba dbName]];
            if(!FILLED(s))continue;
            if([pba isNumeric] && [s doubleValue]==0.0)continue;
        }
        if(fieldsOrControlsButtons && ([pba targetTyp]==ATBU || [pba targetTyp]==ATPORTLET)){
            [lma addObject:pba];
            continue;
        }
        if(fieldsOrControlsParms && ([pba targetTyp]==ATTVCPD)){
            [lma addObject:pba];
            continue;
        }
        if(fieldsOrControlsFields && ([pba targetTyp]==ATTVCSELOBJ)){
            [lma addObject:pba];
            continue;
        }
    }
    if(fieldsOrControlsSortByUI){
        [fieldsOrControls addObjectsFromArray:[[lma sortedArrayUsingKeyOrderArray:[NSArray soaCaseInsensitiveFrom:@"guiNameTrans"]]valuesForKey:@"dbName"]];
    }else{
        [fieldsOrControls addObjectsFromArray:[[lma valuesForKey:@"dbName"]sortedArray]]; //dbnames
    }
}
- (WOElement *)enterConfig;
{
    isConfigMode=YES;
    [self setSelectedRegister:nil];
    if(!FILLED([parmDict ofk:@"p_lastAction"]))[parmDict setObject:@"removeField" forKey:@"p_lastAction"];
    if(FILLED(selectedBoxName))[parmDict setObject:selectedBoxName forKey:@"selectedBoxName"]; // merken fuer leaveconfig, um wieder da hin zu positionieren
    if([self isKindOfClass:[PBWOPosEditor class]]){
        [self setSelectedRegister:@"_common"];
    }else{
        if(FILLED(selectedBoxName) && ![selectedBoxName iE:@"System"]){
            int i,j;
            NSArray *a = [self registers];
            for(i=0,j=[a count];i<j;i++){
                NSString *s = [a oai:i];
                NSArray *a1 = [s componentsSeparatedByString:@"|"];
                if([a1 count]==3){
                    NSString *s1 = [a1 oai:2];
                    if([s1 iE:selectedBoxName]){
                        [self setSelectedRegister:s];
                    }
                }
            }
        }
    }
    [self setSelectedRegisterModify:selectedRegister];
    [self rebuildFieldsInSelectedRegister];
    [self rebuildFieldsOrControl];
    return self;
}
- (BOOL)isConfigModeListe;
{
    return configMode==CONFIGMODE_Liste;
}
- (BOOL)isConfigModeDetail;
{
    return configMode==CONFIGMODE_Detail;
}
- (BOOL)isConfigModeLif;
{
    return configMode==CONFIGMODE_Lif;
}
- (WOElement *)gotoConfigModeDetail;
{
    configMode = CONFIGMODE_Detail;
    if(!selectedRegister)[self setSelectedRegister:[[self registers]firstObject]];
    [self setSelectedRegisterModify:selectedRegister];
    [self rebuildFieldsInSelectedRegister];
    [self rebuildFieldsOrControl];
    return self;
}
- (BOOL)hasNoTV;
{
    return !([self hasTV]);
}
- (WOElement *)gotoConfigModeLif;
{
    configMode = CONFIGMODE_Lif;
    return self;
}
- (WOElement *)fieldsOrControlsToggleUnused;
{
    fieldsOrControlsUnused =! fieldsOrControlsUnused;
    [self rebuildFieldsOrControl];
    return self;
}
- (WOElement *)fieldsOrControlsToggleUsed;
{
    fieldsOrControlsUsed =! fieldsOrControlsUsed;
    [self rebuildFieldsOrControl];
    return self;
}
- (WOElement *)fieldsOrControlsToggleParms;
{
    fieldsOrControlsParms =! fieldsOrControlsParms;
    [self rebuildFieldsOrControl];
    return self;
}
- (WOElement *)fieldsOrControlsToggleSort;
{
    fieldsOrControlsSortByUI =! fieldsOrControlsSortByUI;
    [self rebuildFieldsOrControl];
    return self;
}
- (WOElement *)fieldsOrControlsToggleFields;
{
    fieldsOrControlsFields =! fieldsOrControlsFields;
    [self rebuildFieldsOrControl];
    return self;
}
- (WOElement *)fieldsOrControlsToggleFilled;
{
    fieldsOrControlsFilled =! fieldsOrControlsFilled;
    [self rebuildFieldsOrControl];
    return self;
}
- (WOElement *)fieldsOrControlsToggleButtons;
{
    fieldsOrControlsButtons =! fieldsOrControlsButtons;
    [self rebuildFieldsOrControl];
    return self;
}
- (WOElement *)fieldsOrControlsToggleTags;
{
    fieldsOrControlsTags =! fieldsOrControlsTags;
    [self rebuildFieldsOrControl];
    return self;
}
- (NSString *)fieldsOrControlsToggleTagsSrc;
{
    return [NSSWF @"/Aprica2_%@/Images/%@",[_APP mandant],(fieldsOrControlsTags?@"check_on.gif":@"check_off.gif")];
}
- (NSString *)fieldsOrControlsToggleButtonsSrc;
{
    return [NSSWF @"/Aprica2_%@/Images/%@",[_APP mandant],(fieldsOrControlsButtons?@"check_on.gif":@"check_off.gif")];
}
- (NSString *)fieldsOrControlsToggleFieldsSrc;
{
    return [NSSWF @"/Aprica2_%@/Images/%@",[_APP mandant],(fieldsOrControlsFields?@"check_on.gif":@"check_off.gif")];
}
- (NSString *)fieldsOrControlsToggleFilledSrc;
{
    return [NSSWF @"/Aprica2_%@/Images/%@",[_APP mandant],(fieldsOrControlsFilled?@"check_on.gif":@"check_off.gif")];
}
- (NSString *)fieldsOrControlsToggleParmsSrc;
{
    return [NSSWF @"/Aprica2_%@/Images/%@",[_APP mandant],(fieldsOrControlsParms?@"check_on.gif":@"check_off.gif")];
}
- (NSString *)fieldsOrControlsToggleSortSrc;
{
    return [NSSWF @"/Aprica2_%@/Images/%@",[_APP mandant],(fieldsOrControlsSortByUI?@"check_on.gif":@"check_off.gif")];
}
- (NSString *)fieldsOrControlsToggleUsedSrc;
{
    return [NSSWF @"/Aprica2_%@/Images/%@",[_APP mandant],(fieldsOrControlsUsed?@"check_on.gif":@"check_off.gif")];
}
- (NSString *)fieldsOrControlsToggleUnusedSrc;
{
    return [NSSWF @"/Aprica2_%@/Images/%@",[_APP mandant],(fieldsOrControlsUnused?@"check_on.gif":@"check_off.gif")];
}
- (NSString *)guiNameForCurrentFieldInSelectedRegister;
{
//f. StringWrapper in fieldsInSelectedRegister
    NSString *s=nil,*gn,*dn;
    NSString *string = [currentFieldInSelectedRegister string];
    NSString *zeilennr = [NSSWF @"%03i ",fieldsInSelectedRegisterIndex++];
    if([string hasSecurePrefix:@"<"])return [zeilennr stringByAppendingString:string]; //Format-Anweisung
//guiName des PBDDAttribute bzw. dbName wenn showDescri= NO u. in Klammern der Beispiel-Value des selObj
    if([self selObj] && ![string iE:@"cryptedpw"]){
        PBEO *eo = [self selObj];
        s = [[eo values] ofk:string];
    }
    gn = [[allAttr ofk:string] guiNameTrans];
    dn = [[allAttr ofk:string] dbName];
    if(!FILLED(s))return [NSSWF @"%@%@ (%@)",zeilennr,gn,dn];
    return [[NSSWF @"%@%@ (%@) [%@]",zeilennr,gn,dn,s]abbrevToLength:50];
}
- (NSString *)guiNameForCurrentFieldItem;
{
//f. Strings in fieldsOrControls
//controls woertlich
//suffix * wenn schon irgendwo verbaut
//guiName, evt. uebersetzt
//dbName
//dahinter in klammern den evt. Wert im EO;
    NSString *s=nil,*gn,*dn;
    NSString *string = currentFieldItem;
    NSString *usedMarker=@"";
    if([string hasSecurePrefix:@"<"])return string; //Format-Anweisung
//guiName des PBDDAttribute bzw. dbName wenn showDescri= NO u. in Klammern der Beispiel-Value des selObj
    if([self selObj] && ![string iE:@"cryptedpw"]){
        PBEO *eo = [self selObj];
        s = [[eo values] ofk:string];
    }
    gn = [[allAttr ofk:string] guiNameTrans];
    dn = [[allAttr ofk:string] dbName];
    if([self isInLifDict:string])usedMarker=@" *";
    if(FILLED(s)){
        s = [NSSWF @"[%@]",s];
    }else{
        s = @"";
    }
    if(fieldsOrControlsSortByUI){
        return [[NSSWF @"%@%@(%@) %@",gn,usedMarker,dn,s]abbrevToLength:50];
    }else{
        return [[NSSWF @"%@%@(%@) %@",dn,usedMarker,gn,s]abbrevToLength:50];
    }
}
- (WOElement *)fieldUp;
{
    [self fieldDirection:-1];
    return self;
}
- (WOElement *)fieldDown;
{
    [self fieldDirection:1];
    return self;
}
- (void)fieldDirection:(int)direction;
{
    NSMutableArray *lma = (NSMutableArray *)[self fieldsInSelectedRegister],*lma1=[self lifDictArrrayOfSelectedRegister];
    PBStringWrapper *field;
    NSString *s;
    int ip;
    if((field = [selectedFields firstObject])){
        if([[field string] iE:@"<Ende>"])return;
        ip = [lma indexOfObject:field];
        if(ip == NSNotFound)return;
        field = [lma oai:ip];
        s = [lma1 oai:ip];
        [field retain];
        [s retain];
        [lma removeObjectAtIndex:ip];
        [lma1 removeObjectAtIndex:ip];
        ip+=direction;
        if(ip<0)ip=0;
        if(ip>=[lma count]){
            ip=[lma count]-1;
        }
        [lma insertObject:field atIndex:ip];
        [lma1 insertObject:s atIndex:ip];
        [field release];
        [s release];
    }
}
- (WOElement *)fieldMoveToTargetPos;
{
    NSMutableArray *lma = (NSMutableArray *)[self fieldsInSelectedRegister],*lma1=[self lifDictArrrayOfSelectedRegister];
    PBStringWrapper *field;
    int ip,nip,amount,direction=0;
    NSString *s;
    if([fieldTargetPos hasSecurePrefix:@"+"]){
        amount=[[fieldTargetPos substringFromIndex:1] intValue];
        direction = 1;
    }else if([fieldTargetPos hasSecurePrefix:@"-"]){
        amount=[[fieldTargetPos substringFromIndex:1] intValue];
        direction = 2;
    }else{
        amount=[fieldTargetPos intValue];
    }
    if((field = [selectedFields firstObject])){
        if([[field string] iE:@"<Ende>"])return self;
        ip = [lma indexOfObject:field];
        if(ip == NSNotFound)return self;
        [field retain];
        s = [lma1 oai:ip];
        [s retain];
        [lma removeObjectAtIndex:ip];
        [lma1 removeObjectAtIndex:ip];
        if(direction == 1){
            nip = ip + amount;
        }else if(direction == 2){
            nip = ip - amount;
        }else{
            nip = amount;
            if(nip > ip)nip--; //da urspr. pba jetzt draussen
        }
        if(nip>=[lma count]){
            nip = [lma count]-1;
        }
        if(nip<0)nip=0;
        [lma insertObject:field atIndex:nip];
        [lma1 insertObject:s atIndex:nip];
        [field release];
        [s release];
    }
    return self;
}
- (WOElement *)selectFieldForEdit;
{
    PBStringWrapper *field;
    NSMutableArray *lma = (NSMutableArray *)[self fieldsInSelectedRegister];
    if((field = [selectedFields firstObject])){
        NSString *s = [field string];
        if([s hasSecurePrefix:@"<width "] 
	   || [s hasSecurePrefix:@"<descrWidth "] 
	   || [s hasSecurePrefix:@"<editWidth "] 
	   || [s hasSecurePrefix:@"<bezWidth "] 
	   || [s hasSecurePrefix:@"<guiName "]
           || [s hasSecurePrefix:@"<ESC "]
           || [s hasSecurePrefix:CLASS_PREFIX] 
	   || [s hasSecurePrefix:TEXT_PREFIX] 
	   || [s hasSecurePrefix:IMG_PREFIX] 
	   || [s hasSecurePrefix:NI_PREFIX] 
	   || [s hasSecurePrefix:ZEILEN_PREFIX]
           || [s hasSecurePrefix:BLOCK_PREFIX]
           || [s hasSecurePrefix:HTML_PREFIX]
	   || [s hasSecurePrefix:RASTER_PREFIX]){
            indexOfSelectedField = [lma indexOfObject:field];
            if(indexOfSelectedField == NSNotFound){
                [self setSelectedField:EON];
                return self;
            }
            [self setSelectedField:s];
        }
    }
    [parmDict setObject:@"selectFieldForEdit" forKey:@"p_lastAction"];
    return self;
}
- (WOElement *)submitSelectedRegisterModified;
{
    if(!FILLED(selectedRegisterModify)){
        LOGI(TRANSLATION(@"bitte Name fuer neues Register angeben"));
        return self;
    }
    if([lifDict ofk:selectedRegisterModify]){
        LOGI(TRANSLATION(@"dieses Register gibt es schon; bitte anderen Namen waehlen;"));
        return self;
    }
    if([[selectedRegisterModify componentsSeparatedByString:@"|"]count] != 3){
        LOGI(TRANSLATION(@"falsches Format fuer Registername; Bsp.:\"a|200|Name\""));
        return self;
    }
    [lifDict setSecureObject:[lifDict ofk:selectedRegister] forKey:selectedRegisterModify];
    [lifDict removeObjectForKey:selectedRegister];
    [self setSelectedRegister:selectedRegisterModify];
    [self rebuildFieldsInSelectedRegister];
    return self;
}
- (WOElement *)submitSelectedField;
{
    if(FILLED(selectedField) && indexOfSelectedField!=NSNotFound){
        [(NSMutableArray *)[self lifDictArrrayOfSelectedRegister]replaceObjectAtIndex:indexOfSelectedField withObject:selectedField];
        [[[self fieldsInSelectedRegister]oai:indexOfSelectedField] setString:selectedField];
    }
    return self;
}
- (WOElement *)toggleConfigFocus;
{
    if([[parmDict ofk:@"p_lastAction"]iE:@"removeField"]){
        [parmDict setObject:@"addField" forKey:@"p_lastAction"];
        return self;
    }
    if([[parmDict ofk:@"p_lastAction"]iE:@"addField"]){
        [parmDict setObject:@"removeField" forKey:@"p_lastAction"];
        return self;
    }
    [parmDict setObject:@"removeField" forKey:@"p_lastAction"];
    return self;
}
- (WOElement *)removeField;
{
    int i,j=[selectedFields count],oldPos;
    if(!j)return self;
    oldPos = [fieldsInSelectedRegister indexOfObject:[selectedFields firstObject]];
    if(oldPos < 0)oldPos = 0;
    for(i=0;i<j;i++){
        PBStringWrapper *field = [selectedFields oai:i];
        NSString *s = [field string];
        if([s iE:@"<Ende>"])continue;
        [fieldsOrControls addObject:s]; //nicht uniq, damit feldfolgen mit controls dazwischen intakt bleiben
        [(NSMutableArray *)[self fieldsInSelectedRegister] removeObject:field];
    }
    [self reflectFieldsInSelectedRegister];
    [parmDict setObject:@"removeField" forKey:@"p_lastAction"];
// versuchen wieder in die Naehe zu positionieren
    if(oldPos >= [[self fieldsInSelectedRegister]count])oldPos--;
    if(oldPos < 0)return self; // nix zu machen
    [self setSelectedFields:[NSArray arrayWithObject:[[self fieldsInSelectedRegister]oai:oldPos]]];
    return self;
}
- (WOElement *)copyField;
{
//in Register belassen, kopieren f. paste
    int i,j;
    for(i=0,j=[selectedFields count];i<j;i++){
        PBStringWrapper *field = [selectedFields oai:i];
        NSString *s = [field string];
        if([s iE:@"<Ende>"])continue;
        [fieldsOrControls addObject:s];
    }
    return self;
}
- (void)reflectFieldsInSelectedRegister;
{
// aus Editer-Array, welches stringwrappers enthaelt, zurueck ins lif-Array des Registers
    int i,j;
    NSArray *a = [[self fieldsInSelectedRegister]valuesForKey:@"string"];
    [[self lifDictArrrayOfSelectedRegister] removeAllObjects];
    for(i=0,j=[a count];i<j;i++){
        NSString *s = [a oai:i];
        if([s iE:@"<Ende>"])continue;
        [[self lifDictArrrayOfSelectedRegister] addObject:s];
    }
}
- (NSMutableArray *)lifDictArrrayOfSelectedRegister;
{
    return [lifDict ofk:selectedRegister];
}
- (WOElement *)addField;
{
    NSMutableArray *lma = (NSMutableArray *)[self fieldsInSelectedRegister],*lma1=[self lifDictArrrayOfSelectedRegister];
    int i,j,ip=0;
    PBStringWrapper *field;
    NSString *s;
    if((field = [selectedFields firstObject])){
        ip = [lma indexOfObject:field];
    }
    if(ip < 0)ip = 0; //insertion point
    for(i=0,j=[selectedFieldsOrControls count];i<j;i++){
        int eip = ip + i;
        s = [selectedFieldsOrControls oai:i];
        if(eip >= [lma count]){
            [lma1 addObject:s];
            [lma addObject:[PBStringWrapper stringWrapperWithString:s]];
        }else{
            [lma1 insertObject:s atIndex:ip+i];
            [lma insertObject:[PBStringWrapper stringWrapperWithString:s] atIndex:ip+i];
        }
    }
    [parmDict setObject:@"addField" forKey:@"p_lastAction"];
    return self;
}
- (void)insertString:(NSString *)s;
{
    NSMutableArray *lma = (NSMutableArray *)[self fieldsInSelectedRegister],*lma1=[self lifDictArrrayOfSelectedRegister];
    int ip=0;
    PBStringWrapper *field;
    if((field = [selectedFields firstObject])){
        ip = [lma indexOfObject:field];
    }
    if(ip < 0)ip = 0; //insertion point
    field = [PBStringWrapper stringWrapperWithString:s];
    if(ip >= [lma count]){
        [lma1 addObject:s];
        [lma addObject:field];
    }else{
        [lma1 insertObject:s atIndex:ip];
        [lma insertObject:field atIndex:ip];
    }
}
- (WOElement *)insertBR;
{
    [self insertString:@"<br>"];
    return self;
}
- (WOElement *)insertClass1;
{
    [self insertString:@"<class=1>"];
    return self;
}
- (WOElement *)insertClass2;
{
    [self insertString:@"<class=2>"];
    return self;
}
- (WOElement *)insertClass3;
{
    [self insertString:@"<class=3>"];
    return self;
}
- (WOElement *)insertClass4;
{
    [self insertString:@"<class=4>"];
    return self;
}
- (WOElement *)insertClass5;
{
    [self insertString:@"<class=5>"];
    return self;
}
- (WOElement *)insertClass6;
{
    [self insertString:@"<class=6>"];
    return self;
}
- (NSArray *)fieldsOrControls;
{
    return fieldsOrControls;
}
- (NSArray *)controlFields;
{
return [NSArray arrayWithObjects:@"<tab>",@"<zeilen 4>",@"<zeilen 16>",@"<width 4>",@"<width 8>",@"<width 12>",@"<text 16 bla>",@"<guiName andererGuiName>",@"<pidimg width=100 height=100>",@"<namedIcon width=40 height=39 dbName=storno>",@"<pw>",@"<raster 30>",@"<rasterd>",@"<nodescr>",@"<descrWidth 2>",@"<descrWidth 4>",@"<descrWidth 8>",@"<editWidth 2>",@"<editWidth 4>",@"<editWidth 8>",@"<editWidth 12>",@"<bezWidth 2>",@"<bezWidth 4>",@"<bezWidth 8>",@"<block 12>",@"<endblock>",@"<html <br><br>>",@"<ESC a>",@"<ESC b>",@"<ESC c>",nil];
}
- (WOElement *)loadMyLif;
{
    NSString *s = [NSSWF @"%@/LayoutsUsers/%@/%@.lif",MANDANTPATH,CURRENTUSER,[self name]];
    [self setLastLifPath:s];
    [self setLifEditArea:[NSSWCOF s]];
    return self;
}
- (WOElement *)saveAsMyLif;
{
    NSString *c=lifEditArea;
    if(FILLED(c)){
        NSString *s = [NSSWF @"%@/LayoutsUsers/%@/%@.lif",MANDANTPATH,CURRENTUSER,[self name]];
        [myFM createAllDirsAtPath:[s stringByDeletingLastPathComponent]];
        [c WTF:s];
    }
    return self;
}
- (NSString *)lifStringWithDict:(NSDictionary *)dict;
{
    NSMutableString *s=[NSMutableString stringWithCapacity: 1024];
    NSArray *keys = [[dict allKeys] sortedArray];
    id flds;
    NSString *key,*fld;
    unsigned i,j,n,m;
    for (i=0,n=[keys count];i<n;i++) {
        key = [keys oai: i];
        if(![key iE:@"soseq"]){
            [s appendString: key];
            [s appendString: @"\t-\n"];
        }
        flds = [dict ofk: key];
        if ([flds isKindOfClass:[NSArray class]]) {
            for (j=0,m=[flds count];j<m;j++) {
                fld = [flds oai: j];
                [s appendString: key];
                [s appendString: @"\t"];
                [s appendString: fld];
                if([key iE:SC_LIF_TV]){
                    int customWidth = [[colWidthDict ofk:fld]intValue]; //customwidth
                    if(customWidth)[s appendFormat:@":%i", customWidth];
                }
                [s appendString: @"\n"];
            }
        } else {
            [s appendString: key];
            [s appendString: @"\t"];
            [s appendString: flds];
            [s appendString: @"\n"];
        }
    }
    return s;
}
- (int)editBezWidthPixel;
{
// f. plainFields
    return [currentAsso width] - [currentAsso descrWidthPixel];
}
- (void)buildUpFields:(NSArray *)a forTitle:(NSString *)k;
{
//a enthaelt echte Attribute und NSStrings fuer Formatanweisungen
//nur noch breite setzen; wird von float:left platziert
//<br> macht ein <br clear=all>
//<tab> macht ein 1 raster grosses Element
//keine Fluchtlinien mehr, dafuer einheitliche Breiten
    int i,j,ac=[a count],autoAssoCount=0,width=0;
    NSString *k1=nil,*s;
    PBDDAttribute *pba;
    NSMutableArray *assosInBox; //box to fill
    BOOL nodescr=NO,pw=NO,isBR=NO;
    PBWOAsso *pbas;
    NSString *gn = nil;
    int zeilen=0; //steuert abweichende zeilenzahl der unmittelbar folgenden textarea bzw. Hoehe des Elements
    int raster,descrWidth,editWidth,bezWidth; //ueberschreiben der App-Defaults
    int classNo=0;
    unichar ascii=0;
    BOOL short_fields = [[[_APP configDict]ofk:@"short_fields"]iE:@"J"];
    raster = [_APP raster];
    descrWidth = [_APP descrWidth];
    bezWidth = [_APP bezWidth];
    editWidth = [_APP editWidth];
    if([k iE:@".AUTO"] || [k iE:@"Felder"]){ //jew. erstes Feld der Box
        k1 = nil; 
    }else{
        k1 = k; //aus lif
    }
    if(!ac && ![k1 iE:SC_LIF_COMMON] && ![k1 iE:SC_LIF_SUCHABFR]){
        if(!k1)return; //nix zu machen
        if(![boxDict count]){
            [self setSelectedBoxName:k1]; //auf erste Box positionieren
        }
        [boxDict sofk([NSArray array],k1)];  //customBoxes ohne Felder
        [boxNameArray addObject:k1];
        return;
    }
    assosInBox = [NSMutableArray arrayWithCapacity:20];
    if(!k1)k1 = TRANSLATION(@"Detail");
    if(![boxDict count]){
        [self setSelectedBoxName:k1]; //auf erste Box positionieren
    }
    [boxDict sofk(assosInBox,k1)];
    if([k1 iE:SC_LIF_COMMON]){
        [self setCommonBox:assosInBox];
    }else if([k1 iE:SC_LIF_SUCHABFR]){
        [self setSuchabfrButtons:assosInBox];
    }else{
        [boxNameArray addObject:k1];
    }
    for(i=0,j=[a count];i<j;i++){
        pba = [a oai:i];
        if([pba isKindOfClass:[PBDDAttribute class]]){
            if(![pba isAuthorized])continue;
            if([pba targetTyp]==ATPORTLET){
// Abmessungen bestimmt Portlet selbst
                pbas = [[PBWOAsso alloc]initWith:self andAttr:pba]; // guiName ist PortletName
                portletIndex++;
                goto platzieren;
            }
            if([pba targetTyp]==ATBU){
// ein button
                int w,h;
// bei buttons wird width in px interpretiert: nein, nicht mehr; fuehrte zu verschobenen layouts
                if(width){
                    w = raster * width;
                    width=0;
                }else{
                    w = raster * 3;
                }
                h=LINEHEIGHT;
                
                pbas = [[PBWOAsso alloc]initWith:self andAttr:pba];
                [pbas setWidth:w];
                [pbas setHeight:h];
                goto platzieren;
            }
            pbas = [[PBWOAsso alloc]initWith:self andAttr:pba];
            if(nodescr){
                [pbas setNoDescr:YES];
                nodescr = NO;
            }
            if(pw){
                [pbas setPw:YES];
                pw = NO;
            }
            if(zeilen){
                [pbas setZeilen:zeilen];
                zeilen = 0;
            }
            if(gn){
                [pbas setGuiName:gn];
                gn = nil;
            }
            if(ascii){
                [pbas setAssoID:[NSSWF @"target%i",(int)ascii]];
                [pbas setGuiName:[NSSWF @"%@ ESC-%@",[pbas guiName],[NSString stringWithCharacters:&ascii length:1]]];
                ascii = 0;
            }
            if([pba length]>=50 && ![pbas isTextArea] && !short_fields){
                editWidth = 12;
            }
            [pbas determineSizeDwp:raster * descrWidth ewp:raster * editWidth bwp:raster * bezWidth];
            if(width){
                [pbas setWidth:width * raster];
                width=0;
            }
            editWidth = [_APP editWidth];
            descrWidth = [_APP descrWidth];
            bezWidth = [_APP bezWidth];
platzieren:
            [assosInBox addObject:pbas]; //erstmal alles in eine box
            [pbas release];
            if(isBR){
                [pbas setIsBR:YES];
                isBR = NO;
            }
            [pbas setClassNo:classNo];
            classNo = 0;
       }else{
            s = (NSString *)pba;
            //NSString; Formatieranweisung; in pbas steht letzte platzierte
            // <br> auf erste ganz leere zeile
	    // <nodescr> Bezeichnung abschalten
            // <pw> als Passwortfeld darstellen
            // <invisible> unsichtbar; wird nur vom system eingefuegt
            // <tab> macht raster breites element
            // <class=1> setzt class f. naechstes Element
	    // <raster x> raster umsetzen
            // <rasterd> raster auf default ruecksetzen
// <descrWidth 4> descrWidth auf 4
// <editWidth 4> editWidth auf 4
// <bezWidth 4> bezWidth auf 4
	    // <block 6> <endblock> einen Block der angegebenen Breite  beginnen/beenden
            // <width 5> gesamtbreite des naechsten Elements uebersteuern
            // <text 2 bla, fasel> 2 Rastereinheiten eigener Text; wird wie Feld positioniert
	    // <pidimg width=... height=... > Bild zum Datensatz als Thumbnail einfuegen
            // <namedIcon width=... height=... dbName=... [descr] [bez]> Bild einfuegen: dbName + Wert des Feldes mit "_" verbunden ist Name des gif; descr = descriptor mit anzeigen; bez=bei NamedValues klartext mit anzeigen
            // <guiName xx> fuer folgende Asso diesen guiNamen vorsehen
	    // <ESC x> setzt fuer folgende Asso die AssoID auf targetXX wobei XX der ASCII Code von x ist
            if([s iE:@"<invisible>"]){ //feldbezogene flags u. eigenschaften ruecksetzen; wird vom system eingefuegt, wenn ein unsichtbares Feld uebersprungen wurde
                nodescr=NO;
                pw = NO;
                classNo = 0;
                zeilen = 0;
                width=0;
                gn = nil;
                goto platziert;
            }
            if([s iE:@"<nodescr>"]){
                nodescr=YES;
                goto platziert;
            }
            if([s iE:@"<pw>"]){
                pw=YES;
                goto platziert;
            }
            if([s iE:@"<tab>"]){ //dummy Asso erzeugen
                    PBDDAttribute *pba1;
                    pba1 = [MYDD minimalAttributeNamed:[NSSWF @"tab_%i",autoAssoCount++]];
                    [pba1 setGuiName:@""];
                    pbas = [[PBWOAsso alloc]initWith:self andAttr:pba1];
                    if(width){
                        [pbas setWidth:raster * width];
                        width=0;
                    }else{
                        [pbas setWidth:raster];
                    }
                    [pbas setHeight:LINEHEIGHT];
                    [pbas setIsProtected:YES];
                    [pbas setOnlyDescr:YES];
                    classNo=0;
                    goto platzieren;
            }
            if([s iE:@"<br>"]){
//fuehrt zu einem <br clear=all>
                isBR = YES;
            }
            if([s hasSecurePrefix:@"<guiName "]){
                s = [s substringFromIndex:[@"<guiName " length]];
                gn = TRANSLATION([s substringToIndex:[s length]-1]); //ohne >
                goto platziert;
            }
            if([s hasSecurePrefix:@"<width "]){
                width = [[s substringFromIndex:[@"<width " length]]intValue];
                goto platziert;
            }
            if([s hasSecurePrefix:@"<ESC "]){
                ascii = [[s substringFromIndex:[@"<ESC " length]]characterAtIndex:0];
                goto platziert;
            }
            if([s hasSecurePrefix:CLASS_PREFIX]){
                s = [s substringFromIndex:[CLASS_PREFIX length]];
                classNo = [s intValue];
                goto platziert;
            }
            if([s hasSecurePrefix:TEXT_PREFIX]){
                int rasters;
                s = (NSString *)pba; //s war lowercase, jetzt wieder wie aus lif
                s = [s substringFromIndex:[TEXT_PREFIX length]];
                rasters = [s intValue]; // auch 2-stelllige zahlen zulassen
                if(rasters < 0)rasters = 2;
                if([s length]>1){
                    PBDDAttribute *pba1;
                    s = [s substringFromIndex:2];
                    s = [s substringToIndex:[s length]-1]; //der Nutztext
                    pba1 = [MYDD minimalAttributeNamed:[NSSWF @"text_%i",autoAssoCount++]];
                    [pba1 setGuiName:s]; //lifs sind schon uebersetzt
                    pbas = [[PBWOAsso alloc]initWith:self andAttr:pba1];
                    [pbas setWidth:raster * rasters]; //lines, height, width
                    [pbas setHeight:LINEHEIGHT];
                    [pbas setIsProtected:YES];
                    [pbas setOnlyDescr:YES];
                    goto platzieren;
                 }
            }
            if([s hasSecurePrefix:IMG_PREFIX]){
// <pidimg width=... height=... >
                int w,h,r;
                NSArray *whs,*kv;
                PBDDAttribute *pba1;
                s = [s substringFromIndex:[IMG_PREFIX length]];
                s = [s substringToIndex:[s length]-1]; //ohne ">"
                whs = [s componentsSeparatedByString:@" "];
                if([whs count]!=2){
                    LOGS(([NSSWF @"falsche <img.. zeile: %@",s]));
                    continue;
                }
                
                kv = [[whs oai:0]componentsSeparatedByString:@"="];
                if([kv count]!=2 || ![[kv firstObject]iE:@"width"]){
                    LOGS(([NSSWF @"falsche width in <img.. zeile: %@",s]));
                    continue;
                }
                w = [[kv oai:1]intValue];
                
                kv = [[whs oai:1]componentsSeparatedByString:@"="];
                if([kv count]!=2 || ![[kv firstObject]iE:@"height"]){
                    LOGS(([NSSWF @"falsche height in <img.. zeile: %@",s]));
                    continue;
                }
                h = [[kv oai:1]intValue];
                if(h<LINEHEIGHT)h=LINEHEIGHT;
                pba1 = [MYDD minimalAttributeNamed:[NSSWF @"bild_%i",autoAssoCount++]]; //
                pbas = [[PBWOAsso alloc]initWith:self andAttr:pba1];
                r = w/raster;
                if(w%raster > 0.0)r++;
                [pbas setWidth:r * raster]; //lines, height, width
                [pbas setHeight:h];
                [pbas setIsImage:YES];
                goto platzieren;
            }
            if([s hasSecurePrefix:HTML_PREFIX]){
// <html bla-fasel>
                s = [s substringFromIndex:[HTML_PREFIX length]];
                s = [s substringToIndex:[s length]-1]; //ohne ">"
                pbas = [[PBWOAsso alloc]init];
                [pbas setIsHTMLCarrier:YES];
                [pbas setDbName:s];
                goto platzieren;
            }
            if([s hasSecurePrefix:BLOCK_PREFIX]){
// <block x>
                s = [s substringFromIndex:[BLOCK_PREFIX length]];
                s = [s substringToIndex:[s length]-1]; //ohne ">"
                pbas = [[PBWOAsso alloc]init];
                [pbas setIsHTMLCarrier:YES];
                [pbas setDbName:[NSSWF @"<div class=\"LifBlock\" style=\"width: %ipx;\">",raster * [s intValue]]];
                goto platzieren;
            }
            if([s iE:@"<endblock>"]){
// <endblock>
                pbas = [[PBWOAsso alloc]init];
                [pbas setIsHTMLCarrier:YES];
                [pbas setDbName:@"</div>"];
                goto platzieren;
            }
            if([s hasSecurePrefix:RASTER_PREFIX]){
// <raster x>
                s = [s substringFromIndex:[RASTER_PREFIX length]];
                s = [s substringToIndex:[s length]-1]; //ohne ">"
                raster = [s intValue];
                goto platziert;
            }
            if([s hasSecurePrefix:@"<descrWidth "]){
// <descrWidth x> descrWidth auf x
                s = [s substringFromIndex:[@"<descrWidth " length]];
                s = [s substringToIndex:[s length]-1]; //ohne ">"
                descrWidth = [s intValue];
                goto platziert;
            }
            if([s hasSecurePrefix:@"<editWidth "]){
// <editWidth x> editWidth auf x
                s = [s substringFromIndex:[@"<editWidth " length]];
                s = [s substringToIndex:[s length]-1]; //ohne ">"
                editWidth = [s intValue];
                goto platziert;
            }
            if([s hasSecurePrefix:@"<bezWidth "]){
// <bezWidth x> bezWidth auf x
                s = [s substringFromIndex:[@"<bezWidth " length]];
                s = [s substringToIndex:[s length]-1]; //ohne ">"
                bezWidth = [s intValue];
                goto platziert;
            }
            if([s iE:RASTER_D]){
// <rasterd>
                raster = [_APP raster]; //wieder aus config.dict
                goto platziert;
            }
            if([s hasSecurePrefix:ZEILEN_PREFIX]){
// <zeilen 8>
                s = [s substringFromIndex:[ZEILEN_PREFIX length]];
                s = [s substringToIndex:[s length]-1]; //ohne ">"
                zeilen=[s intValue];
                goto platziert;
            }
            if([s hasSecurePrefix:NI_PREFIX]){
                pbas = [self assoForNIFrom:s];
                if(!pbas)continue;
                goto platzieren;
            }
        }
platziert: ;
    }
}
- (int)lineHeight;
{
    return LINEHEIGHT; //f. wod
}
- (int)descrWidthPixelOr0;
{
    if([currentAsso noDescr])return 0;
    return [currentAsso descrWidthPixel];
}
- (PBWOAsso *)assoForNIFrom:(NSString *)s;
{
// returned eine retained PBWOAsso !
// <namedIcon width=... height=... dbName=... [descr] [bez]> Bild einfuegen: dbName + Wert des Feldes mit "_" verbunden ist Name des gif; descr = descriptor mit anzeigen; bez=bei NamedValues klartext mit anzeigen
    int w,h;
    NSArray *whs,*kv;
    PBDDAttribute *pba1;
    NSString *dbName;
    PBWOAsso *pbas;
    s = [s substringFromIndex:[NI_PREFIX length]];
    s = [s substringToIndex:[s length]-1]; //ohne ">"
    whs = [s componentsSeparatedByString:@" "];
    if([whs count]<3){
        LOGS(([NSSWF @"falsche <namedIcon.. zeile: %@",s]));
        return nil;
    }
    kv = [[whs oai:0]componentsSeparatedByString:@"="];
    if([kv count]!=2 || ![[kv firstObject]iE:@"width"]){
        LOGS(([NSSWF @"falsche width in <namedIcon.. zeile: %@",s]));
        return nil;
    }
    w = [[kv oai:1]intValue];
    kv = [[whs oai:1]componentsSeparatedByString:@"="];
    if([kv count]!=2 || ![[kv firstObject]iE:@"height"]){
        LOGS(([NSSWF @"falsche height in <namedIcon.. zeile: %@",s]));
        return nil;
    }
    h = [[kv oai:1]intValue];
    if(h<LINEHEIGHT)h=LINEHEIGHT;
    kv = [[whs oai:2]componentsSeparatedByString:@"="];
    if([kv count]!=2 || ![[kv firstObject]iE:@"dbName"]){
        LOGS(([NSSWF @"kein dbName in <namedIcon.. zeile: %@",s]));
        return nil;
    }
    dbName = [kv oai:1];
    pba1 = [myTable plainAttrNamed:dbName];
    if(!pba1){
        LOGS(([NSSWF @"falscher dbName in <namedIcon.. zeile: %@",s]));
        return nil;
    }
    pbas = [[PBWOAsso alloc]initWith:self andAttr:pba1];
    [pbas setWidth:w]; //nicht alignen
    [pbas setHeight:h];
    [pbas setIsImage:YES];
    [pbas setIsNI:YES];
    return pbas;
}
- (NSString *)modulName;
{
    return guiName;
}
- (NSString *)bundleDoku;
{
    if([_SESSION lang]){
        NSString *s;
        s = [bundle doku1];
        if(FILLED(s))return s;
    }
    return [bundle doku0];
}
- (void)didSetUpWithBundle;
{
    [_APP executeScriptNamed:[NSSWF @"%@/didSetUpWithBundle",nameForScript] datasource:self parmDict:parmDict];
}
- (NSString *)name;
{
    return [bundle name];
}
- (void)sleep;
{
//    LOGS(@".........3");
    [super sleep];
}
- (WOElement *)_template;
{
//wird erst in appendToResponse aufgerufen; da ist bundle schon bekannt;
    if(!templ){
        NSString *dn = [bundle htmlwodName]; //explizit angegebener geht vor
        if([_APP logActions])LOGS(@"..._template");
        if(!FILLED(dn))dn = [bundle name]; //sonst mit bundle-Name suchen
        [self setTempl:[_APP getTemplateForName:dn]];
        if(!templ && !FILLED([bundle htmlwodName])){ //wenn kein explizites angegeben und mit bundle-name nicht gefunden, noch default probieren
            [self setTempl:[_APP getTemplateForName:@"defaultNew"]];
        }
        if(!templ){
            LOGS(([NSSWF @"html f. Modul %@ konnte nicht erstellt werden",[bundle name]]));
            return nil;
        }
        [self tvfk(templ,@"_template")];
    }
    return templ;
}
- (PBWOEditor *)callingModul;
{
    [callingModul ensureAwakeInContext:[self context]];
    return callingModul;
}
- (void)setNextModul:(PBWOEditor *)nm;
{
    if(nm == self)return;
    if(nm == nextModul)return;
    nextModul = nm; //keine retain-Cycles
}
- (PBWOEditor *)nextModul;
{
    [nextModul ensureAwakeInContext:[self context]];
    return nextModul;
}
- (void)markInitialSearchTookPlace;
{
    initialSearchTookPlace = YES;
}
- (void)bringToFront:(PBWOEditor *)m andPerformInitialSearch:(BOOL)andPerformInitialSearch;
{
    [m ensureAwakeInContext:[self context]];
    if(andPerformInitialSearch)[m performInitialSearch];
    [m markInitialSearchTookPlace]; //auf jedenfall das Flag setzen
    [self setNextModul:m];
    if(![m bundle])return; //beim ersten mal bevor setupWithBundle gelaufen ist
    // doch immer refetch, damit Felder richtig gesteuert werden
    [m refetchEO];
}
- (void)bringToFrontWithInitialSearch:(PBWOEditor *)m;
{
// bei aufrufen aus Menue etc.
    [m setCallingModul:MODUL(@"Home")];
    [self bringToFront:m andPerformInitialSearch:YES]; //standard; bisherige methode
}
- (void)bringToFront:(PBWOEditor *)m;
{
    [self bringToFront:m andPerformInitialSearch:NO]; //standard; bisherige methode
}
- (NSString *)additionalOnLoadFContent;
{
// im didBuildUp Eventscript oder sonst wo ins parmDict schreiben
    NSString *s = [parmDict ofk:@"additionalOnLoadFContent"];
    if(s)return s;
    return @"";
}
- (NSString *)additionalScriptContent;
{
// im didBuildUp Eventscript oder sonst wo ins parmDict schreiben
    NSString *s = [parmDict ofk:@"additionalScriptContent"];
    if(s)return s;
    return @"";
}
- (NSString *)stdScriptSrc;
{
    NSString *scriptf = @"<script src=\"%@/stdScript%i.js\" type=\"text/javascript\"></script>";
    if([_SESSION lang]){
        return [NSSWF scriptf,[_APP resourceURL],1];
    }
    return [NSSWF scriptf,[_APP resourceURL],0];
}
- (NSString *)script;
{
//hat jedes htlmwod, wo Browser_minimal drin ist;
//- externe URLs und DruckURL in neuem Window oeffnen
//onloadF ausfuehren:
//- auf 1. Feld positionieren
//- submitter clearen
//onLoadF kann erst nach komplettem Laden des Body ausgefuehrt werden;
// wird f. jeden request dynamsich ermittelt; statisches JS ist in stdScript0/1
    NSString *onLoadF,*functionContent;
    NSString *druckUrl = [_APP urlToOpenInNewBrowser]; //pdf Druck
    NSString *externalUrl = [_APP externalUrlToOpenInNewBrowser],*scriptResult;
    functionContent = @"document.forms[0].submitter.value=\"\"; document.forms[0].clickedColumnName.value=\"\"; document.forms[0].clickedRowNumber.value=\"\";";
    if([_SESSION timeOut]<=10){
        NSString *exitScript = [NSSWF @"document.location.assign(\"%@\");", [_APP frameSourceLink]];
        if(exitScript)functionContent = [functionContent stringByAppendingString:exitScript];
    }
    if(externalUrl){
        NSString *fcd = [NSSWF @"\n\
    wd = window.open(\"\",\"extern\");\n\
    wd.close();\n\
    wd = window.open(\"%@\",\"extern\");\n\
    ", externalUrl];
        [_APP setExternalUrlToOpenInNewBrowser:nil];
        functionContent = [functionContent stringByAppendingString:fcd];
    }
    if(druckUrl){
        NSString *fcd = [NSSWF @"\n\
    wd = window.open(\"\",\"DruckPDF\");\n\
    wd.close();\n\
    wd = window.open(\"%@\",\"DruckPDF\");\n\
    ", druckUrl];
        [_APP setUrlToOpenInNewBrowser:nil];
        functionContent = [functionContent stringByAppendingString:fcd];
    }
    if(!druckUrl && !externalUrl){
        NSString *s = [self fieldIDToFocusOn];
        if(s) functionContent = [functionContent stringByAppendingString:[NSSWF @" document.getElementById(\"%@\").focus();",s]];
    }
    functionContent = [functionContent stringByAppendingString:[self additionalOnLoadFContent]];
    onLoadF = [NSSWF @"function onLoadF(){ %@ };",functionContent];
    scriptResult = [NSSWF @"var submitOnReturn = false;\n%@\n%@",onLoadF,[self additionalScriptContent]];
    [self setExternalFieldToFocusOn:nil];
    return scriptResult;
}
- (void)resetErrorAssos;
{
    int i,j;
    PBWOAsso *pbas;
    for(i=0,j=[errorAssos count];i<j;i++){
        pbas = [errorAssos oai:i];
        [pbas resetError];
    }
    [errorAssos removeAllObjects];
}
- (WOElement *)attributeButtonActed:(NSString *)actionName;
{
// vorgeparstes Script oder Druck ausfuehren
    PBDDAttribute *pbat = [myTable plainAttrNamed:actionName];
    if(!pbat)return self;
    [parmDict setSecureObject:selObj forKey:@"p_eo"]; // %selObj immer als p_eo verfuegbar machen, damit buttons auch von anderen Scripts aufgerufen werden koennen;
    [parmDict setObject:actionName forKey:@"_actionName"]; //damit er im script abgefragt werden kann
    if([pbat isDruck]){
        [_APP druckPDFNamed:[pbat scriptName] datasource:self parmDict:parmDict];
    }else{
        [_APP executeScriptNamed:[pbat scriptName] datasource:self parmDict:parmDict];
    }
    return self;
}
- (NSArray *)fassosWithName:(NSString *)s;
{
    LMA;
    int i,j;
    for(i=0,j=[fassos count];i<j;i++){
        PBWOAsso *pbas = [fassos oai:i];
        if([[pbas dbName]iE:s]){
            [lma addObject:pbas];
        }
    }
    return lma;
}
- (void)rebuildFassosByName;
{
    int i,j;
    [fassosByName removeAllObjects];
    for(i=0,j=[fassos count];i<j;i++){
        PBWOAsso *pbas = [fassos oai:i];
	
        [fassosByName setSecureObject:pbas forKey:[pbas dbName]];
    }
}
- (void)bu_dbnames;
{
    int i,j;
    for(i=0,j=[fassos count];i<j;i++){
        PBWOAsso *pbas = [fassos oai:i];
        [pbas setGuiName:[pbas dbName]];
    }
}
- (NSMutableDictionary *)fassosByName;
{
    return fassosByName;
}
- (NSMutableDictionary *)disabledFieldNames;
{
    return disabledFieldNames;
}
- (NSMutableDictionary *)enabledFieldNames;
{
    return enabledFieldNames;
}
- (NSMutableDictionary *)hiddenFieldNames;
{
    return hiddenFieldNames;
}
- (BOOL)paNon;
{
    return ([self pendingAction] == pa_non);
}
- (NSString *)paNonS
{
    if([self paNon])return @"J"; // no pending action
    return @"N";
}
- (NSString *)gotoCurrentLaunchedModuleAction;
{
// Action f. Klick auf geoeffnete Module
    return [NSSWF @"gotoCurrentLaunchedModule%i",currentLaunchedModuleIndex];
}
- (void)gotoCurrentLaunchedModuleNr:(int)i;
{
    [self bringToFront:[[_SESSION launchedModuls]oai:i]];
}
- (WOElement *)doku;
{
//Hilfe zum Modul aufrufen
    PBWOBundleDoku *e = MODUL(@"doku");
    [e setCallingModul:self];
    [e loadCustomDoku];
    [self bringToFront:e];
    return self;
}
- (BOOL)isConfigMode;
{
    return isConfigMode;
}
- (WOElement *)exit;
{
    [_SESSION terminate];
    return self;
}
- (WOElement *)addToPersonal;
{
    [_SESSION addToPersonal:self];
    return self;
}
- (WOElement *)removeFromPersonal;
{
    [_SESSION removeFromPersonal:self];
    return self;
}
- (void)closeModule;
{
// Modul beenden
// aus instanceDict und launchedModuls raus
// Modulen, die dieses als callingModul gesetzt haben, callingModul clearen;
// auf das Modul davor platzieren in launchedModuls
    NSArray *a = [_SESSION launchedModuls];
    int i=0,j = [a count]-1;
    PBWOEditor *e;
    [_SESSION setModulToClose:self]; // hier noch retainen bis man es gefahrlos releasen kann
    while(j>=0){
        e = [a oai:j];
        if(e == self){
            [(NSMutableArray *)[_SESSION launchedModuls]removeObjectAtIndex:j];
            [(NSMutableDictionary *)[_SESSION instanceDict]removeObjectForKey:[self name]];
            i=j-1;
        }else{
            if([e callingModul]==self){
                [e setCallingModul:nil];
            }
        }
        j--;
    }
// vorheriges Modul holen
    if(i>=0 && [a count]>i){
        e = [a oai:i];
    }else{
        e=MODUL(@"Home");
    }
    [self bringToFront:e];
}
/*
- retain;
{
    if([self retainCount] < 10){
        PRINTCURRENTSTACK;
    }
    return [super retain];
}
*/
- (PBWOEditor *)gotoStart;
{
    PBWOEditor *e=nil;
    e=MODUL(@"Home");
    if(e){
        [self bringToFront:e];
        return e;
    }else{
        LOGI(TRANSLATION(@"Probleme mit Home-Modul"));
        return self;
    }
}
- (WOElement *)gotoHelpdesk;
{
    PBWOEditor *e = MODUL(@"HelpdeskV3");
    [self bringToFront:(PBWOEditor *)e];
    return self;
}
- (WOElement *)gotoZwischenablage;
{
    PasteboardEWO *e;
    PBSQLQualifier *q;
    if(!(e=(PasteboardEWO *)MODUL(@"PasteboardE")))return self;
// auf tabelle und modul vorselektieren, aber nicht cmq setzen;
    q = [PBSQLQualifier qualifierWithString:[NSSWF @"eo_entityname = '%@' and modul = '%@'",[myTable dbName],[self name]]];
    SUCH_EXTERNAL(e,q);
    return self;
}
//f. Assos
- (BOOL)_fieldIsDisabled:(NSString *)s;
{
// wird von Asso aufgerufen
    if(!s)return NO;
    if(allFieldsDisabled && !([enabledFieldNames ofk:s]!=nil))return YES;
    return ([disabledFieldNames ofk:s]!=nil);
}
- (BOOL)allFieldsDisabled;
{
// das ist etwas anderes als anzeigemodus; nur die Felder werden gesperrt, Funktionen gehen noch;
    return allFieldsDisabled;
}
- (void)setAllFieldsDisabled:(BOOL)yn;
{
    allFieldsDisabled = yn;
    if(!yn)[disabledFieldNames removeAllObjects];
    if(yn)[enabledFieldNames removeAllObjects];
}
- (void)setAnzeigemodus:(BOOL)yn;
{
    anzeigemodus = yn;
}
- (BOOL)anzeigemodus;
{
    return anzeigemodus;
}
- (void)setCreate_ButtonIsDisabled:(BOOL)yn;{create_ButtonIsDisabled=yn;}
- (void)setDuplicate_ButtonIsDisabled:(BOOL)yn;{duplicate_ButtonIsDisabled=yn;}
- (void)setDelete_ButtonIsDisabled:(BOOL)yn;{delete_ButtonIsDisabled=yn;}
//f. htmlwod bindings, die von WO verlangt werden
- (id)ignore;{return nil;}
- (void)setIgnore:(id)obj;{}
// DialogMode
// confirmation
- (void)confirm_ja;
{
    [_SESSION set_rv:@"J"];
    [_APP continueScript];
}
- (void)confirm_nein;
{
    [_SESSION set_rv:@"N"];
    [_APP continueScript];
}
// ---- bis hierher ehemal. PBWOBrowserComponent
ACCESSClassm(tvcSortCol,setTvcSortCol,PBWOTVCCol);
ACCESSClassm(bundle, setBundle, PBWOBundle)
ACCESSClassm(duplicatedObj, setDuplicatedObj, PBEO)
ACCESSm(masterEntityName, setMasterEntityName)
ACCESSClassm(myTable, setMyTable, PBDDTable)
ACCESSClassm(masterEO, setMasterEO, PBEO)
ACCESSClassm(positionsTabellen,setPositionsTabellen,NSArray);
ACCESSClassm(lastCombinedQ, setLastCombinedQ, PBSQLQualifier)
ACCESSClassm(staticQ,setStaticQ,PBSQLQualifier);
ACCESSClassm(callingMQ,setCallingMQ,PBSQLQualifier);
ACCESSClassm(suchFelderQ,setSuchFelderQ,PBSQLQualifier);
ACCESSClassm(ma,setMa,NSMutableArray)
ACCESSClassm(selObj, setSelObj, PBEO)
ACCESSClassm(externalFieldToFocusOn,setExternalFieldToFocusOn,PBWOAsso);
ACCESSm(combiSuchContent,setCombiSuchContent);
ACCESSm(customWidthTF,setCustomWidthTF);
- (int)fetchLimit;
{
    return fetchLimit;
}
- (void)setFetchLimit:(int)i;
{
    fetchLimit=i;
}
- (NSString *)currentBoxName;
{
    return currentBoxName;
}
- (void)setNeedsSave:(BOOL)yn;
{
    needsSave = yn;
}
- (NSMutableArray *)visibleTVAttr;
{
    return visibleTVAttr;
}
- _componentDefinition;
{
    return nil;
}
- init;
{
    if(!(self = [super init]))return nil;
    MA(fieldsOrControls);
    MD(colWidthDict);
    MD(allAttr);
    MD(lifDict);
    MD(portletDict);
    MD(boxDict);
    MA(errorAssos);
    MD(fassosByName);
    MD(disabledFieldNames);
    MD(enabledFieldNames);
    MD(hiddenFieldNames);
    MD(changedInRequest);
    MA(fassos);
    MA(boxNameArray);
    MA(boxNameArrayBak);
    MA(registerActions);
    MA(registerActionsBak);
    MD(parmDict);
    MD(lifFieldDict);
    MA(clearOnSelObjChanged);
    MA(refreshOnSelObjChanged);
    MA(stateArray);
    assoIDCounter = 0;
    callingModul=nil;
    nextModul=nil;
    anzeigemodus = NO;
    initialSearchTookPlace = NO;
    [self setTempl:nil];
    [self setMyTable:nil];
    [self setCurrentAction:nil];
    [self setBundle:nil];
    isConfigMode = NO;
    configMode = CONFIGMODE_Detail;
    create_ButtonIsDisabled = NO;
    duplicate_ButtonIsDisabled = NO;
    delete_ButtonIsDisabled = NO;
    fieldsOrControlsTags = YES;
    fieldsOrControlsButtons = YES;
    fieldsOrControlsFields = YES;
    fieldsOrControlsFilled = NO;
    fieldsOrControlsParms = YES;
    fieldsOrControlsSortByUI = YES;
    fieldsOrControlsUsed = YES;
    fieldsOrControlsUnused = YES;
    allFieldsDisabled = NO;
    portletIndex = 0;
    countCombinedQ = 0;
    [self setFetchLimit:[_APP fetchLimit]];
    [self setPendingAction:pa_non];
    [self setSuchFelderQ:nil]; //wird bei Suchen gesetzt
    [self setStaticQ:nil]; //wird in init von customModulen gesetzt
    [self setCallingMQ:nil]; //wird in customFindPresel gesetzt
    [self setPositionsTabellen:nil];
    uebernMode = UEB_NONE;
    currentPage = 0;
    MA(columns);
    MA(filterQs);
    MA(visibleTVAttr); // f. configuration
    MA(allTVAttr); // f. configuration
    selectedObjects = [[NSMutableArray alloc]initWithCapacity:fetchLimit];
    ma = [[NSMutableArray alloc]initWithCapacity:fetchLimit];
    maOffset = 0;
    
    [self setExternalFieldToFocusOn:nil];
    isMaximized = YES;
    isMaximizedDetail = YES;
   if([_APP logActions])LOGS(@"...init");
   return self;
}
- (NSString *)currentPbaDisplayString;
{
    NSString *s;
    int customWidth;
    s = [NSSWF @"%@ (%@)",[currentPba guiNameTrans], [currentPba dbName]];
    customWidth = [[colWidthDict ofk:[currentPba dbName]]intValue];
    if(customWidth){
        s = [s stringByAppendingFormat:@":%i",customWidth];
    }else{
        s = [s stringByAppendingFormat:@"(%i)",[currentPba widthForColumn]];
    }
    return s;
}
- (WOElement *)recentlyChanged;
{
// zuletzt geaenderte; anzahl fetchlimit; sortierung auf ldate aendern
    if(hasStatisticFields){
// die TV einstellen, soa erzeugen; nicht speichern;
        [self setSoseq:@"ldate:d"];
        [self suchInternalQ:nil];
    }
    return self;
}
- (WOElement *)combiSucheActed;
{
//    +... Modulkuerzel
//combi-suchfeld fuer suche ueber mehrere textfelder
// leer = alles
// <wert><space>{+,++,+++}{&}
// & alle Begriffe and-verknuepft mit wildcards drumherum in allen cs-feldern; max. fetchlimit
// normal hoert suche mit erstem gefundenen auf; erweiterten Suchumfang festlegen mit + ++ +++ bis zu fetchlimit
// Schleife ueber csFelder der Tabelle:
//    exakt
//    wildcard:
//      bei num. Feldern entfaellt WildCard
//      bei char Feldern: prefix, infix
    NSString *pkn = [myTable primaryKeyName];
    NSArray *csa = [myTable csAttrNames];
    int i,j;
    NSDictionary *returnDict;
    NSString *nutzString,*nutzStringWC;
    BOOL and_wc = NO;
    BOOL extendedSearch = NO;
    int min_results = 1;
    int extendedSearchLimit = [[[_APP configDict]ofk:@"extendedsearchlimit"]intValue];
    LMA;
    NSArray *a;
    LMAN(nutzStringA);
    if(extendedSearchLimit < 1)extendedSearchLimit=10;
    [filterQs removeAllObjects];
    if(!FILLED(combiSuchContent)){
        [self suchInternalQ:nil];
        return self;
    }
    if([combiSuchContent iE:@"?"]){
        LOGI(TRANSLATION(@"leer = alles suchen; sonst: Suchbegriff(e)[leer]Steuercodes"));
        LOGI(TRANSLATION(@"+,++,+++ fuer mehr Ergebnisse;"));
        LOGI(TRANSLATION(@"& fuer Und-verknuepfung aller Begriffe"));
    }
// Eventscript combiSucheActed aufrufen; dort koennen Geheimcodes abegfragt werden; erkennt das Script einen
// Geheimcode, fuehrt es die Suche selbst durch und liefert _
    returnDict = [_APP executeScriptNamed:[NSSWF @"%@/combiSucheActed",nameForScript] datasource:self parmDict:parmDict];
    if([combiSuchContent iE:@"?"])return self;
    if([[returnDict ofk:@"scriptRC"] iE:@"N"])return self;
    if([combiSuchContent hasSecurePrefix:@"+"] && ![combiSuchContent rangeOfString:@" "].length){
        NSString *kuerzel = [combiSuchContent substringFromIndex:1];
        if(FILLED(kuerzel)){
            PBWOEditor *pbe = [_SESSION instanceForKuerzel:kuerzel];
            if(pbe)[self bringToFront:pbe];
            return self;
        }
    }
    min_results = [[[_APP configDict]ofk:@"min_results"]intValue];
    if(min_results > fetchLimit)min_results=fetchLimit;
    if(!min_results){
        min_results=1;
        if(![[csa firstObject]iE:pkn])min_results = 5; // wenn nicht primaer nach primarykey gesucht wird, mehr treffer;
    }
// Eingabe parsen
    nutzString = combiSuchContent;
    a = [combiSuchContent componentsSeparatedByString:@" "];
    if([a count] > 1){
        NSString *sc = [a lastObject];
        if(FILLED(sc) && [sc isSearchCode]){
// falls sc etwas anderes als +,f,& enthaelt, nicht verwenden
            if([sc rangeOfString:@"+++"].length){
                min_results = fetchLimit;
                extendedSearch = YES;
            }else if([sc rangeOfString:@"++"].length){
                min_results *= 10;
                extendedSearch = YES;
            }else if([sc rangeOfString:@"+"].length){
                min_results *= 3;
                extendedSearch = YES;
            }
            if(min_results > fetchLimit)min_results=fetchLimit;
            if([sc rangeOfString:@"&"].length)and_wc = YES;
            nutzString = [combiSuchContent substringToIndex:[combiSuchContent length] - ([sc length] + 1)];
        }
    }
    if(and_wc){
        a = [nutzString componentsSeparatedByString:@" "];
        for(i=0,j=[a count];i<j;i++){
            NSString *s = [a oai:i];
            if(FILLED(s))[nutzStringA addObject:[NSSWF @"%%%@%%",[s sqlWildCardEscapedString]]];
        }
        if([nutzStringA count]==0)and_wc = NO;
    }
    nutzStringWC = [[nutzString sqlWildCardEscapedString]replace:@" " with:@"%"];
    if(extendedSearch){
        j=[csa count]; // alle suchfelder durchgehen
    }else{
        j=MIN(extendedSearchLimit,[csa count]); // wenn nicht mind. ein + eingegeben, nur die Felder bis zum extendedSearchLimit durchsuchen
    }
    countCombinedQ = 0;
    for(i=0;i<j;i++){  // schleife ueber zu beruecksichtigende combisuchfelder
        NSString *csName = [csa oai:i];
        PBDDAttribute *pba;
        pba = [myTable plainAttrNamed:csName];
        if(and_wc){
            if([pba dataTyp]!=DT_INT){
                LMAN(andQA);
                int i1,j1;
                for(i1=0,j1=[nutzStringA count];i1<j1;i1++){
                    // NutzstringA enthaelt die Elemente schon in %..% eingeschlossen
                    PBSQLQualifier *q = [PBSQLQualifier qualifierWithString:[NSSWF @"%@ like '%@'",csName,[nutzStringA oai:i1]]];
                    if(q)[andQA addObject:q];
                }
                if([andQA count]){
                    [lma addObject:[PBSQLQualifier andQualifierWithArray:andQA]];
                    if([self sfqArray:lma willReachMin_Results:min_results])break;
                 }
            }
            continue; // naechstes Suchfeld
        }
        if([pba dataTyp]==DT_INT){
            if([nutzString isNumeric]){
                // INT kann nur mit numerischem nutzstring gesucht werden
                // rein numerische Eingabe ohne Spaces: exakter match ist gemeint
                [lma addObject:[PBSQLQualifier qualifierWithString:[NSSWF @"%@ = %i",csName,[nutzString intValue]]]];
                if([self sfqArray:lma willReachMin_Results:min_results])break;
            }
        }else{
            // exakt
            [lma addObject:[PBSQLQualifier qualifierWithString:[NSSWF @"%@ = '%@'",csName,nutzString]]];
            if([self sfqArray:lma willReachMin_Results:min_results])break;
            // prefix
            [lma addObject:[PBSQLQualifier qualifierWithString:[NSSWF @"%@ like '%@%%'",csName,nutzStringWC]]];
            if([self sfqArray:lma willReachMin_Results:min_results])break;
	    // suffix
            [lma addObject:[PBSQLQualifier qualifierWithString:[NSSWF @"%@ like '%%%@'",csName,nutzStringWC]]];
            if([self sfqArray:lma willReachMin_Results:min_results])break;
            // infix
            [lma addObject:[PBSQLQualifier qualifierWithString:[NSSWF @"%@ like '%%%@%%'",csName,nutzStringWC]]];
            if([self sfqArray:lma willReachMin_Results:min_results])break;
        }
    }
    if(!countCombinedQ){ // min_result wurde nicht erreicht
        [self setSuchFelderQ:[PBSQLQualifier orQualifierWithArray:lma]];
    }
    [self evaluateQualifiers];
    return self;
}
- (BOOL)sfqArray:(NSArray *)lma willReachMin_Results:(int)min_results;
{
// nur interne Methode f. combiSuche
// testet, ob ein aus dem lma als or-qualifiert gebauter potentieller suchfelderq genuegend Treffer ergibt
// wenn ja, wird suchfelderQ, countCombinedQ und lastCombinedQ gesetzt
    PBSQLQualifier *combined_cand,*sfq_cand;
    int countq;
    if(!lma || ![lma count])return NO;
    sfq_cand = [PBSQLQualifier orQualifierWithArray:lma];
    combined_cand = [self combinedQWith:sfq_cand];
    countq = [self countQ:combined_cand];
    if(countq>=min_results){
        countCombinedQ = countq;
        [self setSuchFelderQ:sfq_cand];
        [self setEffectiveCombinedQ:combined_cand];
        return YES;
    }
    return NO;
}
- (BOOL)hasRegister;
{
    return FILLED([self registerFieldDBName]);
}
- (NSString *)registerFieldDBName;
{
    return [bundle registerFieldDBName];
}
- (NSString *)registerFieldGuiName;
{
    return [[myTable plainAttrNamed:[self registerFieldDBName]]guiNameTrans];
}
- (NSString *)wasDuplicate;
{
    return (wasDuplicate?@"J":@"N");
}
- (void)setUpWithBundle:(PBWOBundle *)b;
{
    NSString	*en;
    PBDDAttribute *pbat;
    if(!b)return;
    [self setBundle:b]; //wg. name
    [self setNameForScript:[self name]];
    if([_SESSION lang]){
        NSString *s = [b guiName1];
        if(!FILLED(s))s=[b guiName];
        [self setGuiName:s];
    }else{
        [self setGuiName:[b guiName]];
    }
    en = [[self bundle]entityName];
    if(FILLED(en)){
        [self setMyTable:[MYDD tableNamed:en]];
        [self setPositionsTabellen:[MYDD positionsTabellenForTablenamed:en]];
    }
    hasStatisticFields = ([myTable hasStatisticFields]);
    [self determineStaticBerecht];
    [self setAnzeigemodus:(![self hasEditierBerecht])];
    isPosition = NO; //master-detail -> detail
    needsMasterEO = ![b needsNoMasterEO];
    hasPositionsnr = NO;
    wasDuplicate = NO;
    if((pbat = [myTable plainAttrNamed:@"masterkey"])){ //calling modul muss masterEntityName als myTable haben u. selObj; masterkey ist dann [selObj primaryKey]
        if(FILLED([pbat refdTableName])){
            isPosition = YES;
            [self setMasterEntityName:[pbat refdTableName]];
            if([myTable plainAttrNamed:@"positionsnr"]){
                hasPositionsnr = YES;	//wird dann autom. hochgezaehlt
            }
        }
    }
    [self setCallingModul:nil];
    [self determineAttributes];
    [self determineRegisterActions];
    [self loadLif];
    [self buildUpTVAndRegisters]; // macht u.a. builduptv
    [self setSoseq:[[_SESSION moduleSoseq] ofk:[self name]]];
// nicht immer; nur wenn aus Menue heraus aufgerufen wird; sonst kann es passieren, dass ein gesperrter Satz in selObj steht und Actions aus Scripts nicht mehr gehen;    [self performInitialSearch]
    [parmDict setObject:[self name] forKey:@"modulname"];
    [parmDict setSecureObject:[[self myTable]dbName] forKey:@"mytable"];
    [self didSetUpWithBundle];
}
- (void)performInitialSearch;
{
// f. subclasses
    if(initialSearchTookPlace)return;
    if(![[myTable type] iE:SC_Abstract] && ![bundle initialSearchOff]){
        [self evaluateQualifiers];
    }
    initialSearchTookPlace = YES;
}
- (NSMutableArray *)allExceptVisibleTVAttr;
{
    LMA;
    int i,j;
    PBDDAttribute *pba;
    for(i=0,j=[allTVAttr count];i<j;i++){
        int tt;
        pba = [allTVAttr oai:i];
        tt = [pba targetTyp];
        if(([visibleTVAttr indexOfObject:pba]==NSNotFound) && (tt == ATTVCSELOBJ))[lma addObject:pba];
    }
    [lma sortUsingKeyOrderArray:[NSArray soaCaseInsensitiveFrom:@"guiName"]];
    return lma;
}
- (NSString *)currentPbaGuiName;
{
    NSString *s=nil,*dbn=[currentPba dbName];
    if([dbn hasSecurePrefix:NI_PREFIX])return dbn;
    if([selectedObjects count] && ![dbn iE:@"cryptedpw"]){
        PBEO *eo = [selectedObjects firstObject];
        s = [[eo values] ofk:dbn];
    }
    if(!FILLED(s))return [NSSWF @"%@ (%@)",[currentPba guiNameTrans],dbn];
    return [[NSSWF @"%@ (%@) [%@]",[currentPba guiNameTrans],dbn,s]abbrevToLength:50];
}
- (BOOL)mayLeaveConfig;
{
//wenn spalten, dann muessen auch attribute configuriert werden
    return (![self colCount] || [visibleTVAttr count]>0);
}
- (WOElement *)removeFromVisibleTVAttr;
{
    int i,j;
    for(i=0,j=[selectedVisibleTVAttrs count];i<j;i++){
        [visibleTVAttr removeObject:[selectedVisibleTVAttrs oai:i]];
    }
    return self;
}
- (WOElement *)setCustomWidth;
{
    int i,j,customWidth = [customWidthTF intValue];
    if(customWidth < 0)customWidth=0;
    if(customWidth > 400)customWidth=400;
    for(i=0,j=[selectedVisibleTVAttrs count];i<j;i++){
        PBDDAttribute *pba = [selectedVisibleTVAttrs oai:i];
        if(!customWidth){
            [colWidthDict removeObjectForKey:[pba dbName]];
        }else{
            [colWidthDict setObject:NSS(customWidth) forKey:[pba dbName]];
        }
    }
    return self;
}
- (WOElement *)addToVisibleTVAttr;
{
    //hinter selektiertes einfuegen
    int i,j,ip=0;
    PBDDAttribute *pba;
    if((pba = [selectedVisibleTVAttrs firstObject])){
        ip = [visibleTVAttr indexOfObject:pba];
    }
    if(ip < 0)ip = 0; //insertion point
    for(i=0,j=[selectedAllTVAttrs count];i<j;i++){
        int eip = ip + i;
        pba = [selectedAllTVAttrs oai:i];
        if(eip >= [visibleTVAttr count]){
            [visibleTVAttr addObject:pba];
        }else{
            [visibleTVAttr insertObject:pba atIndex:ip+i];
        }
    }
    return self;
}
- (WOElement *)visibleTVAttrUp;
{
    return [self visibleTVAttrDirection:-1];
}
- (WOElement *)visibleTVAttrDown;
{
    return [self visibleTVAttrDirection:1];
}
- (WOElement *)visibleTVAttrDirection:(int)direction;
{
    PBDDAttribute *pba;
    int ip;
    if((pba = [selectedVisibleTVAttrs firstObject])){
        ip = [visibleTVAttr indexOfObject:pba];
        if(ip == NSNotFound)return self;
        [visibleTVAttr removeObjectAtIndex:ip];
        ip+=direction;
        if(ip<0)ip=0;
        if(ip>=[visibleTVAttr count]){
            [visibleTVAttr addObject:pba];
        }else{
            [visibleTVAttr insertObject:pba atIndex:ip];
        }
    }
    return self;
}
- (WOElement *)visibleTVAttrMoveToTargetPos;
{
    PBDDAttribute *pba;
    int ip,nip,amount,direction=0;
    if([visibleAttrTargetPos hasSecurePrefix:@"+"]){
        amount=[[visibleAttrTargetPos substringFromIndex:1] intValue];
        direction = 1;
    }else if([visibleAttrTargetPos hasSecurePrefix:@"-"]){
        amount=[[visibleAttrTargetPos substringFromIndex:1] intValue];
        direction = 2;
    }else{
        amount=[visibleAttrTargetPos intValue];
    }
    if((pba = [selectedVisibleTVAttrs firstObject])){
        ip = [visibleTVAttr indexOfObject:pba];
        if(ip == NSNotFound)return self;
        [visibleTVAttr removeObjectAtIndex:ip];
        if(direction == 1){
            nip = ip + amount;
        }else if(direction == 2){
            nip = ip - amount;
        }else{
            nip = amount;
            if(nip > ip)nip--; //da urspr. pba jetzt draussen
       }
        if(nip<0)nip=0;
        if(nip>=[visibleTVAttr count]){
            [visibleTVAttr addObject:pba];
        }else{
            [visibleTVAttr insertObject:pba atIndex:nip];
        }
    }
    return self;
}
- (void)executetempscript;
{
// wird von Button in System-Register aufgerufen
    if([_APP isSecure]){
        LOGI(TRANSLATION(@"Durch Commandline-Option -secure unterbunden"));
        return;
    }
    SCRIPT([parmDict ofk:@"tempscript"]);
}
- (PBWOEditor *)datasource;
{
    return self;
}
- (void)createexamplescript;
{
    NSString *script = EON;
    NSString *templateTempScript = [NSSWCOF [NSSWF @"%@/TempScriptTemplate.txt",MANDANTPATH]];
    if(!templateTempScript)templateTempScript = [NSSWCOF [NSSWF @"%@/TempScriptTemplate.txt",GLOBALCONFIGPATH]];
    if(!templateTempScript){
        LOGS(@"TempScriptTemplate.txt nicht gefunden");
        return;
    }
    script = [NSSWF templateTempScript,[myTable dbName]];
    script = [script stringByAppendingString:[_APP attributAuflistungForTable:myTable withDoku:YES]];
    [parmDict setSecureObject:script forKey:@"tempscript"];
}
- (void)savetempscript;
{
// wert aus tempscriptname ist filename
    NSString *fn;
    if([_APP isSecure]){
        LOGI(TRANSLATION(@"Durch Commandline-Option -secure unterbunden"));
        return;
    }
    if(!FILLED([parmDict ofk:@"tempscriptname"])){
        LOGI(TRANSLATION(@"bitte Filename angeben"));
        return;
    }
    fn = [NSSWF @"%@/Scripts/%@/%@",MANDANTPATH,[self name],[parmDict ofk:@"tempscriptname"]];
    [myFM createAllDirsAtPath:[fn stringByDeletingLastPathComponent]];
    [[parmDict ofk:@"tempscript"] WTF:fn];
}
- (void)loadtempscript;
{
// wert aus tempscriptname ist filename
    NSString *fn;
    if(!FILLED([parmDict ofk:@"tempscriptname"])){
        LOGI(TRANSLATION(@"bitte Filename angeben"));
        return;
    }
    fn = [NSSWF @"%@/Scripts/%@/%@",MANDANTPATH,[self name],[parmDict ofk:@"tempscriptname"]];
    [parmDict setSecureObject:[NSSWCOF fn] forKey:@"tempscript"];
}
- (void)listtempscript;
{
// aus mandantendirectory Scripts/mdodulname alle filenamen lesen und in tempscript stellen
    NSString *scriptPath = [NSSWF @"%@/Scripts/%@",MANDANTPATH,[self name]];
    NSArray *a = [myFM directoryContentsAtPath:scriptPath];
    [parmDict setSecureObject:[a componentsJoinedByString:@"\n"] forKey:@"tempscript"];
}
- (void)buildUpTVAndRegisters;
{
    NSMutableArray *pa = [NSMutableArray arrayWithCapacity:10];
    NSArray *a,*lifTV;
    NSMutableArray *lifa;
    int attrC;
    int i,j;
    NSString *k;
    [visibleTVAttr removeAllObjects];
    [colWidthDict removeAllObjects];
    [allTVAttr removeAllObjects];
    [allTVAttr addObjectsFromArray:[allAttr allValues]]; //f. config-Sicht
    [self addNamedIconsToAllTVAttr]; //dummy Attribute f. namedIcons reinmachen
    lifTV = [lifDict ofk:SC_LIF_TV]; //Auswahl u. Reihenfolge der Spalten
    if(lifTV){
        for(i=0,j=[lifTV count];i<j;i++){ //enthaelt namen
            NSString *s = [lifTV oai:i];
            PBDDAttribute *pba;
            if([s hasSecurePrefix:NI_PREFIX]){
                pba = [MYDD minimalAttributeNamed:s];
                [pba setGuiName:s];
                [pba setLength:1];
            }else{
                NSArray *a1 = [s componentsSeparatedByString:@":"];
                if([a1 count]>1){
                    int customWidth = [[a1 oai:1]intValue];
                    NSString *k = [a1 firstObject];
                    if(customWidth < 0)customWidth = 0;
                    if(customWidth > 400)customWidth = 400;
                    pba = [allAttr ofk:k];
                    [colWidthDict setObject:NSS(customWidth) forKey:k];
                }else{
                    pba = [allAttr ofk:s];
                }
            }
            if(!pba)continue;	//gar kein attr.
            if(![pba isAuthorized])continue;
            [visibleTVAttr addObject:pba];
            if([visibleTVAttr count] >= NUM_OF_COL_TO_SHOW)break;
        }
    }else{
        [allTVAttr sortUsingSelector:@selector(compareForSequence:)]; //damit wichtigste felder vorne sind
        for(i=0,j=[allTVAttr count];i<NUM_OF_COL_TO_SHOW && i<j;i++){
            [visibleTVAttr addObject:[allTVAttr oai:i]];
        }
    }
    [self buildUpTV:visibleTVAttr];
    a = [[lifDict allKeys]sortedArrayUsingSelector:@selector(compareBySecondIntField:)];
    attrC = 0;
    [boxDict removeAllObjects];
    [boxNameArray removeAllObjects];
    assoIDCounter = 0;
    [clearOnSelObjChanged removeAllObjects];
    [refreshOnSelObjChanged removeAllObjects];
    [[self _subcomponents] removeAllObjects];
    [fassos removeAllObjects]; // sind schon TV cAssos drin, die wir nicht wollen
    portletIndex = 0;
    for(i=0,j=[a count];i<j;i++){ //box names
        k = [a oai:i];
        if([k iE:SC_LIF_Unres] || [k iE:SC_LIF_Unknown] || [k iE:SC_LIF_TV] || [k iE:@"soseq"] || [k iE:SC_LIF_SS] ){
            continue;
        }
        lifa = [lifDict ofk:k];
        [self filterAttrNames:lifa pa:pa]; //in pa stehen dann nur noch die bekannten, die es als attribute auch gibt
        attrC += [pa count]; //feststellen, ob Felder verbaut werden
        [self buildUpFields:pa forTitle:[self nameForLifdictKey:k]];
    }
    if(!attrC){ //bisher wurden keine Felder verbaut -> wahrscheinlich neues Modul, kein Lif, daher alle bekannten verbauen
        [self buildUpFields:[[allAttr allValues]sortedArrayUsingSelector:@selector(compareForSequence:)] forTitle:@"Felder"];
    }
    [self rebuildFassosByName];
    [_APP executeScriptNamed:[NSSWF @"%@/didBuildUp",nameForScript] datasource:self parmDict:parmDict];
    [boxNameArrayBak removeAllObjects];
    [boxNameArrayBak addObjectsFromArray:boxNameArray];
    [registerActionsBak removeAllObjects];
    [registerActionsBak addObjectsFromArray:registerActions];
}
- (void)removeRegisterActionWithGuiName:(NSString *)s;
{
    int i;
    for(i=[registerActions count]-1;i>=0;i--){
        PBActionO *pbaction = [registerActions oai:i];
        if([[pbaction guiName]iE:s])[registerActions removeObjectAtIndex:i];
    }
}
- (void)restoreBoxNameArray;
{
    [boxNameArray removeAllObjects];
    [boxNameArray addObjectsFromArray:boxNameArrayBak];
    [registerActions removeAllObjects];
    [registerActions addObjectsFromArray:registerActionsBak];
}
- (void)createStdScripts;
{
    LOGI(@"neu machen wie in Workbench; auch Edit-Buttons der Workbench");
}
- (NSString *)printFormAuflistung;
{
    NSString *s = EON;
    int ii,jj;
    NSArray *a1 = [myTable plainAttributes];
    s = [s stringByAppendingString:@"// %selObj hat diese Attribute:\n"];
        for(ii=0,jj=[a1 count];ii<jj;ii++){
            PBDDAttribute *pba = [a1 oai:ii];
            s = [s stringByAppendingFormat:@"gosub checkPage\nv $sp1,$ty,l,'%@\nv $sp2,$ty,l,%%*.%@\n$ty,+,$cr\n",[pba guiName],[pba dbName]];
            if([pba hasVL]){
                int i1,j1;
                for(i1=0,j1=[[pba vl]count];i1<j1;i1++){
                    PBVLO *pbvlo = [[pba vl]oai:i1];
                    s = [s stringByAppendingFormat:@"//\t\t%@\t%@\n",[pbvlo value],[pbvlo bez]];
                }
            }
        }
        return s;
}
- (void)addNamedIconsToAllTVAttr;
{
//alle im lifDict vorkommenden namedIcons auch in allTVAttr als dummy-Attribute rein
//damit koennen Sie in visibleTVAttr ruebergeklickt werden und werden in lifTV gespeichert
//und es koennen TV-Assos daraus gemacht werden, um die NamedIcons auch anzuzeigen in der richtigen Spalte
    NSArray *lifDictArrays = [lifDict allObjects];
    int i,j;
    for(i=0,j=[lifDictArrays count];i<j;i++){
        NSArray *a = [lifDictArrays oai:i];
        int i1,j1;
        if(![a isKindOfClass:[NSArray class]])continue; // soseq ist string, gibt's aber nimmer
        for(i1=0,j1=[a count];i1<j1;i1++){
            NSString *s = [a oai:i1];
            PBDDAttribute *pba;
            if(![s hasSecurePrefix:NI_PREFIX])continue;
            pba = [MYDD minimalAttributeNamed:s];
            [pba setGuiName:s];
            [pba setLength:1];
            [allTVAttr addObjectUniq:pba];
        }
    }
}
- (void)redrawAfterLeaveConfig;
{
    [self setTempl:nil];
    [self determineRegisterActions];
    [self buildUpTVAndRegisters];
    [self didSetUpWithBundle];
}
- (void)buildUpTV:(NSArray *)aa;
{
    int i,j,nocts = NUM_OF_COL_TO_SHOW;
    PBDDAttribute *pba;
    NSString *dbn;
    PBWOAsso *pbas;
    PBWOTVCCol *column;
    //columns aufbauen
//reentrant f. redrawAfterLeaveConfig
//LOGS(@"builduptv");
    //reihenfolge beibehalten aus LIF
    [columns removeAllObjects];
    for(i=0,j=[aa count];i<j;i++){
        BOOL isNI;
        pba = [aa oai:i];
        if(!FILLED(pba))continue; //wg. EON
        dbn = [pba dbName];
        isNI = [dbn hasSecurePrefix:NI_PREFIX]; //named Icon
        if(!isNI){
            if([pba targetTyp] != ATTVCSELOBJ)continue;
            if(![pba isVisible]){
                continue;
            }
        }
        if([columns count] >= nocts)break;
        if(isNI){
            pbas = [self assoForNIFrom:dbn];
            [pbas setWidth:LINEHEIGHT]; //masse vom lif interessieren hier nicht
            [pbas setHeight:LINEHEIGHT];
        }else{
            pbas = [[PBWOAsso alloc]initWith:self andAttr:pba];
        }
        column = [[PBWOTVCCol alloc]initWithWOAsso:pbas];
        [columns addObject:column];
        [pbas release];
        [column release];
    }
}
- (PBWOTVCCol *)columnWithName:(NSString *)s;
{
// zum einfachen umkonfigurieren in scripts
    int i,j;
    if(!FILLED(s))return nil;
    for(i=0,j=[columns count];i<j;i++){
        PBWOTVCCol *col = [columns oai:i];
        if([[col dbName]iE:s])return col;
    }
    return nil;
}
- (void)dealloc
{
    [fieldsOrControls release];
    [selectedFields release];
    [selectedFieldsOrControls release];
    [colWidthDict release];
    [fieldsInSelectedRegister release];
    [currentRegister release];
    [selectedRegister release];
    [disabledFieldNames release];
    [portletDict release];
    [stateArray release];
    [changedInRequest release];
    [enabledFieldNames release];
    [hiddenFieldNames release];
    [registerActions release];
    [lifFieldDict release];
    [selectedRegisterModify release];
    [newRegisterName release];
    [commonBox release];
    [suchabfrButtons release];
    [nameForScript release];
    [currentFieldItem release];
    [clearOnSelObjChanged release];
    [refreshOnSelObjChanged release];
    [fieldTargetPos release];
    [lifEditArea release];
    [lastLifPath release];
    [selectedField release];
    [currentFieldInSelectedRegister release];
    [parmDict release];
    [allAttr release];
    [errorAssos release];
    [fassos release];
    [fassosByName release];
    [boxNameArray release];
    [boxNameArrayBak release];
    [registerActionsBak release];
    [boxDict release];
    [lifDict release];
    [myTable release];
    [guiName release];
    [selectedBoxName release];
    [currentAction release];
    [bundle release];
    [templ release];
    [waitingForName release];
    [masterEO release];
    [tvcSortCol release];
    [positionsTabellen release];
    [customWidthTF release];
    [lastCombinedQ release];
    [suchFelderQ release];
    [staticQ release];
    [visibleTVAttr release];
    [allTVAttr release];
    [callingMQ release];
    [masterEntityName release];
    [duplicatedObj release];
    [ma release];
    [soa release];
    [externalFieldToFocusOn release];
    [selectedObjects release];
    [selObj release];
    [columns release];
    [filterQs release];
    [combiSuchContent release];
    [tvNewSearchInSortCol release];
    [soseq release];
    [super dealloc];
}
- (BOOL)mayOffsetWeiter;
{
    if(needsSave || ![self paNon])return NO;
    if([ma count] == fetchLimit)return YES;
    return NO;
}
- (NSString *)offsetS;
{
    return NSS(maOffset);
}
- (int)maOffset; { return maOffset;}
- (int)countCombinedQ; { return countCombinedQ;}
- (NSString *)offsetWeiterS;
{
    return TRANSLATION(@"weitere Seiten");
}
- (NSString *)offsetZurueckS;
{
    return TRANSLATION(@"vorherige Seiten");
}
- (void)offsetWeiter;
{
    if(![self mayOffsetWeiter])return;
    LOG_ACTION;
    maOffset += fetchLimit;
    [self neuSuchen]; //mit lastCombinedQ
}
- (BOOL)mayOffsetZurueck;
{
    if(needsSave || ![self paNon])return NO;
    if(maOffset >= fetchLimit)return YES;
    return NO;
}
- (void)offsetZurueck;
{
    if(![self mayOffsetZurueck])return;
    LOG_ACTION;
    maOffset -= fetchLimit;
    [self neuSuchen]; //mit lastCombinedQ
}
- (NSString *)callingModulName;
{
    NSString *s = [[self callingModul] guiName];
    if(isPosition){
        if(masterEO){
            if(!FILLED(s)){
                return [NSSWF @"(%@)",[masterEO primaryKey]];
            }else{
                return [NSSWF @"(%@ %@)",s,[masterEO primaryKey]];
            }
        }else{
            if(!FILLED(s)){
                return @"---";
            }else{
                return [NSSWF @"(%@ ---)",s];
            }
        }
    }else{
        if(!FILLED(s))return EON;
        return [NSSWF @"(%@)",s];
    }
}
- (BOOL)ruecksprung_ButtonIsDisabled;
{
    return (![self paNon] || callingModul == nil);
}
- (BOOL)suche_ButtonIsDisabled;
{
    return ![self paNon];
}
- (BOOL)recentlyChanged_BuIsDisabled;
{
    return !hasStatisticFields;
}
- (BOOL)create_ButtonIsDisabled;
{
    return (create_ButtonIsDisabled || ![self paNon] || [self anzeigemodus] || (isPosition && needsMasterEO && !masterEO));
}
- (BOOL)duplicate_ButtonIsDisabled;
{
    return (duplicate_ButtonIsDisabled || ![self paNon] || [self anzeigemodus] || (isPosition && needsMasterEO && !masterEO) || selObj==nil);
}
- (BOOL)delete_ButtonIsDisabled;
{
// wenn geaendert, wuerde bei will/didDelete mit ungesicherten Eingabewerten gearbeitet werden;
// z.B. LS-Pos, menge veraendern, nicht sichern, loeschen -> Lagerbestand stimmt nicht mehr
    return (delete_ButtonIsDisabled || pendingAction == pa_upd || [self anzeigemodus] || (isPosition && needsMasterEO && !masterEO) || [[self selectedObjects] count] == 0);
}
- (BOOL)save_ButtonIsDisabled;
{
    return (!selObj || [self anzeigemodus]);
}
- (BOOL)undo_ButtonIsDisabled;
{
    return !needsSave;
}
- (BOOL)bookmark_ButtonIsDisabled;
{
    return ( ![self paNon] || ([selectedObjects count]==0));
}
- (BOOL)refetchEO_ButtonIsDisabled;
{
    return (![self paNon] || !selObj);
}
- (void)bookmark;	//selObj bookmarken, falls EO
{
    int i,j;
    if([self bookmark_ButtonIsDisabled])return;
    LOG_ACTION;
    j = [selectedObjects count];
    for(i=0;i<j;i++){
        PBEO *eo = [selectedObjects oai:i];
        if([eo isKindOfClass:[PBEO class]]){
// hier pasteboard satz schreiben; keine Doubletten
            PBEO *pb;
            NSString *pk = [eo primaryKey],*qf;
            if(!FILLED(pk))continue;
            qf = [NSSWF @"eo_pk = '%@' and eo_entityname = '%@' and modul = '%@'",pk,[eo entityName],[self name]];
            if(testExistQf(@"pasteboard",qf))continue;
            pb = NEW_EO(@"pasteboard");
            [pb tvfk(pk,@"eo_pk")];
            [pb tvfk([eo entityName],@"eo_entityname")];
            [pb tvfk([eo descri],@"eo_descr")];
            [pb tvfk([self name],@"modul")];
            [pb tvfk([self guiName],@"modulgui")];
            [pb tvfk([myTable guiName],@"eo_tablegui")];
            INSRT(pb);
        }
    }
}
- (void)setCallingModul:(PBWOEditor *)m;
{
//macht uebernMode aus
//setzt callingMQ auf nil
//dieser muss danach, falls benoetigt gesetzt werden
    [self setUebernMode:UEB_NONE];
    [self setCallingMQ:nil];
    if(m==self)return;
    if(m != callingModul){
        [callingModul release];
        callingModul = [m retain];
    }
    [callingModul ensureAwakeInContext:[self context]];
}
- (void)addEo:(PBEO *)someObject;
{
    //interne Methode;
    [self setPendingAction:pa_ins];
    [ma addObject:someObject];
    [self positionTo:BOT];
    [self setNeedsSave:YES];
}
- (void)_selObjChanged;
{
    // im prinzip nix zu tun, da alles dynamisch bestimmt wird, insbes. prepareData
    // in subClasses evt. f. Cacheing-Funktionalitaet nutzen, z.B. bei dynamic Editoren
    // PRINTCURRENTSTACK;
    [parmDict setSecureObject:selObj forKey:@"p_eo"];
    [_APP executeScriptNamed:[NSSWF @"%@/selObjChanged",nameForScript] datasource:self parmDict:parmDict];
    [clearOnSelObjChanged makeObjectsPerformSelector:@selector(clear)]; // cleared Portlets, die sich dafuer registriert haben
    [refreshOnSelObjChanged makeObjectsPerformSelector:@selector(refresh)]; // refreshed Portlets, die sich dafuer registriert haben
}
- (void)ausZwischenablage;
{
// such-Qualifier weg und neu bilden aus Saetzen, die in zwischenablage liegen fuer die Tabelle
// Schluessel besorgen
    NSArray *a = [_APP getStringArrayAsResultFrom:[NSSWF @"select eo_pk from pasteboard where eo_entityname = '%@'",[myTable dbName]]];
    if([a count]){
        PBSQLQualifier *q = [PBSQLQualifier orQualiFromArray:a forDbName:[myTable primaryKeyName]];
        [self suchInternalQ:q];
    }else{
        LOGI(TRANSLATION(@"nichts geeignetes in Pasteboard"));
    }
}
- (void)ausHistorie;
{
// such-Qualifier weg und neu bilden aus Saetzen, die in session.$table_keys liegen fuer die Tabelle
// Schluessel besorgen
    NSArray *a = [[_SESSION parmDict]ofk:[NSSWF @"%@_keys",[myTable dbName]]];
    if([a count]){
        PBSQLQualifier *q = [PBSQLQualifier orQualiFromArray:a forDbName:[myTable primaryKeyName]];
        {
// entspricht suchinternal
            [self setSuchFelderQ:q];
            [filterQs removeAllObjects];
            [self evaluateQualifiers];
            {
// aufruffolge noch setzen
                int i,j;
                for(i=0,j=[ma count];i<j;i++){
                    PBEO *eo = [ma oai:i];
                    [eo tvfk((NSS([a indexOfObject:[eo primaryKey]])),@"aufruffolge")];
                }
            }
        }
    }
}
- (void)ruecksprung;
{
//reiner ruecksprung zu callingmodul
    if([self ruecksprung_ButtonIsDisabled])return;
    LOG_ACTION;
    
    if([self callingModul]){
        [callingModul refetchEO]; //prueft selbst pa_non; autom. aktualisieren;
        [callingModul setExternalFieldToFocusOn:[callingModul waitingForName]];
        [callingModul setWaitingForName:nil];
        [self bringToFront:callingModul];
        [self setCallingModul:nil]; //cleared auch callingMQ
    }
}
- (void)determineAttributes;
{
    [allAttr removeAllObjects];
    [allAttr addEntriesFromDictionary:[NSDictionary lookupDictForArray:[myTable plainAttributes] key:@"dbName"]];
//evt. noch weitere attr. hier dazu nehmen aus best. abstract tables oder im bundle angegebene
//evt. irgendwelche davon wegnehmen
//statisch invisible auf jeden Fall raus
    [allAttr removeObjectsForKeys:[myTable dbNamesNotVisible]];
}
/*
obsolet; war nicht so toll;
- (NSArray *)allFilledAttr;
{
// nur Attribute aus allAttr, die auch was in der DB haben
    NSArray *a = [allAttr allValues];
    LMA;
    int i,j;
    unsigned int total;
    double min_perc = 0.05; //mindestens soviel muessen gefuellt sein, damit das Feld angezeigt wird
    double filled_perc;
    if(![myTable isRealTable])return a;
    total = [[_APP getSingleValueAsResultFrom:[NSSWF @"select count(*) from %@",[myTable dbName]]]intValue];
    if(!total)return a; //table ganz leer
    for(i=0,j=[a count];i<j;i++){
        PBDDAttribute *pba = [a oai:i];
        int tt = [pba targetTyp];
        int dt = [pba dataTyp];
        int filled;
        if(tt==ATBU || tt==ATTVCPD || tt==ATPORTLET){
            [lma addObject:pba];
            continue;
        }
        if(![pba isDB]){
            [lma addObject:pba];
            continue;
        }
        if(dt==DT_CHAR || dt==DT_BOOL || dt==DT_CHAR_FIX){
            filled = [[_APP getSingleValueAsResultFrom:[NSSWF @"select count(*) from %@ where (%@ <> '' and %@ is not null)",[myTable dbName],[pba dbName],[pba dbName]]]intValue];
        }else if(dt==DT_MONEY || dt==DT_INT || dt==DT_FLOAT || dt==DT_DATE || dt==DT_DATETIME){
            filled = [[_APP getSingleValueAsResultFrom:[NSSWF @"select count(*) from %@ where (%@ <> 0 and %@ is not null)",[myTable dbName],[pba dbName],[pba dbName]]]intValue];
        }else{
            filled = 0;
        }
        filled_perc = (double)filled / (double)total;
//        LOGS(([NSSWF @"%@ filled %i of %i (%0.2f %%)",[pba dbName],filled,total,filled_perc * 100]));
        if(filled_perc < min_perc)continue;
        [lma addObject:pba];
        [pba setCustom:NSS(filled)];
    }
    return lma;
}
*/
- (void)createDefaultLayout;
{
    LMA;
    LMAN(lmatv);
    int i,j;
    NSArray *a = [allAttr allValues];
    PBDDTable *ago = [MYDD tableNamedCheap:@"_AGENERAL_O"];
    PBDDTable *vid_g = [MYDD tableNamedCheap:@"_VID_GENERAL"];
    for(i=0,j=[a count];i<j;i++){
        PBDDAttribute *pba = [a oai:i];
        NSString *s = [pba dbName];
        int tt = [pba targetTyp];
        //diese attribute ausnehmen; sie kommen ins System-Tab
        if(![ago plainAttrNamed:s] && ![vid_g plainAttrNamed:s]){
            [lma addObjectUniq:s];
            if(tt==ATBU || tt==ATTVCPD || tt==ATPORTLET)continue;
            if([lmatv count]<7)[lmatv addObjectUniq:s];
        }
    }
    [lma sort];
    [lmatv sort];
    
    [lifDict setSecureObject:lma forKey:@"a|200|Detail-Ansicht"];
    [self addScriptTab];
    [lifDict setSecureObject:lmatv forKey:SC_LIF_TV];
    [lifDict setObject:[NSMutableArray array] forKey:SC_LIF_COMMON];
    [lifDict setObject:[NSMutableArray array] forKey:SC_LIF_SUCHABFR];
}
- (BOOL)hasEditierBerecht;
{
    return hasEditierBerecht; //Editierberechtigung
}
- (void)setHasEditierBerecht:(BOOL)yn;
{
    hasEditierBerecht = yn;
}
- (void)determineStaticBerecht;
{
    hasEditierBerecht = YES; //schliesst moneyfields mit ein
    
    //sonderflags ziehen staerker als ModulBerechtigungen
    if(IS_ROOT){
        return;
    }
    if([_SESSION readOnly]){
        hasEditierBerecht = NO;
    }
}
- (BOOL)notInserting;
{
    return ((pendingAction != pa_ins));
}
- (NSString *)notInsertingS;
{
// f. Scripting
    return ([self notInserting]?@"J":@"N");
}
- (NSString *)insertingS;
{
// f. Scripting
    return ([self notInserting]?@"N":@"J");
}
- (BOOL)notRoot;
{
    return !IS_ROOT;
}
- (void)setUebernMode:(int)i;
{
    uebernMode = i;
}
- (int)uebernMode;
{
    return uebernMode;
}
- (int)pendingAction;{return pendingAction;}
- (void)setPendingAction:(int)v;
{
    pendingAction = v;
}
- (BOOL)needsSave;{return needsSave;}
- (void)aValueChanged;
{
    if([self paNon]){
        [self setPendingAction:pa_upd];
        [self setNeedsSave:YES];
//        PRINTCURRENTSTACK;
   }
}
- (PBSQLQualifier *)rechercheQ;
{
    LMA;
    PBSQLQualifier *q;
    if(suchFelderQ)[lma addObject:suchFelderQ];
    if(staticQ)[lma addObject:staticQ];
    if(![lma count]){
        q = nil;
    }else{
        q = [PBSQLQualifier andQualifierWithArray:lma];
    }
    return q;
}
- (PBSQLQualifier *)combinedQ;
{
    return [self combinedQWith:suchFelderQ];
}
- (PBSQLQualifier *)combinedQWith:(PBSQLQualifier *)sfq;
{
//wann immer gesucht wird, wird es mit diesem Qualifier getan; er wird ueber suchFelderQ oder callingMQ indirekt beeinflusst
    LMA;
    PBSQLQualifier *q;
// normalerweise dynamisch gesetzt
    if(sfq)[lma addObject:sfq]; // kann auch PBNOTHINGQualifier oder PBALLQualifier sein
    if(callingMQ)[lma addObject:callingMQ];
// in init oder setupWithBundle gesetzt
    if(staticQ)[lma addObject:staticQ];
// Filter dazu
    [lma addObjectsFromArray:filterQs];
    if(![lma count]){
        q = PBALLQ;
    }else{
        q = [PBSQLQualifier andQualifierWithArray:lma];
    }
    return q;
}
- (void)setEffectiveCombinedQ:(PBSQLQualifier *)q;
{
    if(!q)return;
    [self setLastCombinedQ:q]; //fuer neuSuchen
    [stateArray addObject:[PBWOEditorState stateOf:self]];
    while([stateArray count]>10)[stateArray removeObjectAtIndex:0];
}
- (void)suche_zurueck;
{
// das Ergebnis der letzten Suche anzeigen
// besser: letzte treffermenge mit seite und selObj wiederherstellen
    [stateArray secureRemoveLastObject];
    if([stateArray count]){
        PBWOEditorState *state = [stateArray lastObject];
        [ma removeAllObjects];
        [ma addObjectsFromArray:[state ma]];
        [self setLastCombinedQ:[state lastCombinedQ]];
        maOffset = [state maOffset];
        countCombinedQ = [state countCombinedQ];
        [self gatherSelectedObjects];
    }
}
- (BOOL)hasStatisticFields;
{
    return hasStatisticFields;
}
- (void)determineRegisterActions;
{
// haben nichts mit normalen Actions zu tun
// sind positions-Register Actions
    int i,j;
    [registerActions removeAllObjects];
    for(i=0,j=[positionsTabellen count];i<j;i++){
        NSString *dbName = [positionsTabellen oai:i];
        NSString *actionName = [NSSWF @"gotoPositionen_%@",dbName];
        NSString *actionGuiName = [NSSWF @">%@",[[MYDD tableNamedCheap:dbName]guiName]];
        PBActionO *_action =  [PBActionO actionWithName:actionName gui:TRANSLATION(actionGuiName)];
        if(_action){
            [registerActions addObject:_action];
        }
    }
}
- (void)setAktiv;
{
    LOG_ACTION;
    
    [self setAktivTo:SC_BOOL_TRUE];
}
- (void)setInaktiv;
{
    LOG_ACTION;
    
    [self setAktivTo:SC_BOOL_FALSE];
}
- (void)setAktivTo:(NSString *)s;
{
    NSArray *a;
    int i,j;
    PBEO *eo=nil;
    if(![self hasEditierBerecht])return;
    if(![self paNon])return;
    a = [self selectedObjects];
    for(i=0,j=[a count];i<j;i++){
        eo = [a oai:i];
        [eo tvfk(s,NAME_OF_AKTIV_FLAG)];
        if(![self ceoh_will:@"willUpdate:" eo:eo])continue;
        [eo tvfk(s,NAME_OF_AKTIV_FLAG)];
        UPDAT(eo);
    }
    [_APP executeScriptNamed:[NSSWF @"%@/selObjChanged",nameForScript] datasource:self parmDict:parmDict];
}
- (void)refetchEO;
{
    if(![self refetchEO_ButtonIsDisabled]){
        LOG_ACTION;
        [_APP refetchEO:selObj]; //fetched nochmal alle attr., laesst das PBEO aber als solches;
    }
    [self _selObjChanged];
}
- (void)neuSuchen;
{
//aufgerufen von offsetWeiter/zurueck und nach Sortierungsaenderung, wenn treffermenge > fetchlimit
//kein rebuildSoa, damit evt. temporaeres verwendet wird
    NSArray *a;
    a = [_APP getEOs:[myTable dbName] qualifier:lastCombinedQ offset:maOffset count:fetchLimit soa:soa];
    if(![a count]){
        LOGI(TRANSLATION(@"nichts gefunden"));
    }
    isMaximized = YES;
    [self takeObjects:a];
    countCombinedQ = [self countQ:lastCombinedQ];
// nicht mastereo ruecksetzen, da auch bei umsortierung und weiterblaettern aufgerufen
}
- (int)countQ:(PBSQLQualifier *)q;
{
//feststellen, wieviel saetze der Qualifier liefert
    NSString *sql;
    NSString *wc = [q string];
    if([myTable isRealTable]){
        if(FILLED(wc)){
            sql = [NSSWF @"select count(*) from %@ where %@",[myTable dbName],wc];
        }else{
            sql = [NSSWF @"select count(*) from %@",[myTable dbName]];
        }
        return [[_APP getSingleValueAsResultFrom:sql]intValue];
    }
    return 0;
}
- (BOOL)suchSuccessfulExternalQ:(PBSQLQualifier *)q;
{
//von modulen ausserhalb aufzurufen
//liefert YES, wenn etwas gefunden wurde
//typischerweise Ergebnisse von Verarbeitungsvorgaengen uebergeben
//wurde nichts gefunden, vorherigen Stand wieder herstellen
    PBSQLQualifier *callingMQBackup,*cqc;
    int i;
    LMAN(filterBackup);
    if(![self paNon]){
        LOGI(([NSSWF TRANSLATION(@"%@ hat ungespeicherte Aenderungen."),guiName]));
        return NO;
    }
    callingMQBackup = [[callingMQ copy]autorelease];
    [filterBackup addObjectsFromArray:filterQs];
    [self setCallingMQ:nil];
    [filterQs removeAllObjects];
    cqc = [self combinedQWith:q];
    i = [self countQ:cqc];
    if(!i){
//vorherigen zustand wieder herstellen
        [self setCallingMQ:callingMQBackup];
        [filterQs addObjectsFromArray:filterBackup];
        LOGI(TRANSLATION(@"nichts gefunden"));
        return NO;
    }else{
        [self setSuchFelderQ:q];
        [self setEffectiveCombinedQ:cqc];
    }
    maOffset = 0;
    currentPage = 0;
    [self neuSuchen];
    [self setCallingModul:nil];  //cleared auch callingMQ; uebernehmen geht dann nimmer;
    [self setMasterEO:nil];
    return YES;
}
- (void)evaluateQualifiers;
{
    [self setEffectiveCombinedQ:[self combinedQ]];
    maOffset = 0;
    currentPage = 0;
    [self neuSuchen];
    [self setMasterEO:nil];
}
- (void)suchInternalQ:(PBSQLQualifier *)q;
{
//nur intern aufrufen
//suchfelderq setzen; callingModulq belassen; eos immer nehmen, auch wenn nix gefunden
//bei  combi-suche, recentlyChanged
    [self setSuchFelderQ:q];
    [filterQs removeAllObjects];
    [self evaluateQualifiers];
}
- (void)executeCallingMQ:(PBSQLQualifier *)q;
{
//bei Preselection verwenden
//callingMQ setzen, suchfelderQ leeren aber nicht auf stack, eos auf jeden fall nehmen, auch wenn keine gefunden
//Modul bleibt im callingMQ gefangen, kommt nicht aus eigener Kraft heraus;
//nur noch bei PBWOLookup
    [self setCallingMQ:q];
    [self setSuchFelderQ:nil];
    [filterQs removeAllObjects];
    [self evaluateQualifiers];
}
- (void)create;
{
    PBEO	*newEO;
    // if([self create_ButtonIsDisabled])return; doch zulassen von scripts; nur nicht ueber oberflaeche; z.B. bei LS
    LOG_ACTION;
    if(!(newEO = [_APP createEOforEN:[myTable dbName]]))return;
    wasDuplicate = NO;
    [newEO retain];
    if(isPosition && masterEO){ // posEO
        if(![[[_APP configDict]ofk:@"no_duplicate"]iE:@"J"]){
            // gleichlautende Values uebernehmen, die duplicate=J haben
            // evt. initialwerte werden ueberschrieben!
            // hat ein masterEO gleichlautende Summen-Felder, sollten diese auf duplicate=N gesetzt werden;
            [newEO takeValuesOfSameNameFromEo:masterEO];
        }
	//von masterEO den primaryKey als masterKey nehmen
        [newEO tvfk([masterEO primaryKey],@"masterkey")];
    }
    [self _didCreate:newEO];
    [self addEo:newEO];
    [newEO release];
// auf 1. Register
    [self gotoFirstBox];
}
- (void)duplicate;	//Ko
{
    PBEO	*newEO,*oldEO;
    if([self duplicate_ButtonIsDisabled])return;
    LOG_ACTION;
    if(!(newEO = [_APP createEOforEN:[myTable dbName]]))return;
    [newEO retain];
    oldEO = selObj;
    [newEO takeValuesFromDictionaryToDuplicate:[oldEO values]];
    if(isPosition && masterEO){ //posEO;nur den masterkey uebernehmen; 
        [newEO tvfk([masterEO primaryKey],@"masterkey")];
    }
    [self setDuplicatedObj:oldEO];
    [self _didCreate:newEO];
    [self addEo:newEO];
    wasDuplicate = YES;
    [newEO release];
    [parmDict setSecureObject:newEO forKey:@"p_eo"];
    [_APP executeScriptNamed:[NSSWF @"%@/didDuplicate",nameForScript] datasource:self parmDict:parmDict];
// das neue EO ist noch nicht inserted, daher koennen die Positionen noch nicht kopiert werden; das geht erst im didInsert
// auf 1. Register
    [self gotoFirstBox];
}
- (void)delete;
{
    LOG_ACTION;
    
        //sofort loeschen; aus eos rausnehmen; tv refresh;
    if(pendingAction == pa_ins){
        [self setPendingAction:pa_non];
        [self _delete];
        wasDuplicate = NO;
        [self setNeedsSave:NO];
        return;
    }
    if([self delete_ButtonIsDisabled])return;
    if([_APP verifyDelete]){
        NSString *s = [parmDict ofk:@"delete_confirmed"];
        if(FILLED(s)){
            if([s iE:@"N"]){
                LOGI((TRANSLATION(@"Abbruch.")));
                [parmDict removeObjectForKey:@"delete_confirmed"];
                return;
            }
        }else{
            [_APP executeScriptNamed:@"verifyDelete" datasource:self parmDict:parmDict];
            return;
        }
    }
    [parmDict removeObjectForKey:@"delete_confirmed"];
    if(pendingAction == pa_upd || [self paNon]){
	NSAutoreleasePool *mp = [NSAutoreleasePool new];
        int i,j;
        int newSelection=[ma indexOfObject:[selectedObjects firstObject]];
        
//positionen autom. mitloeschen
//Berechtigungsprinzip: wer das mastereo loeschen darf, darf auch die positionen mit loeschen
        for(i=0,j=[selectedObjects count];i<j;i++){
            PBEO *eo = [selectedObjects oai:i];
            [self setSelObj:eo]; //weil mehrere auf einmal geloescht werden koennen u. die will/did u. Scripts immer auf selObj gehen;
// setSelObj ist hier gefahrlos, weil damit kein Seiteneffekt ausgeloest wird und danach in _delete ohnehin neu positioniert wird
// in Zukunft $p_eo nehmen in scripts
            if(![self _willDelete:eo])continue;
            [_APP deleteEO:eo];
            if(positionsTabellen){
                int ii,jj;
                NSString *pk = [eo primaryKey];
                for(ii=0,jj=[positionsTabellen count];ii<jj;ii++){
                    NSString *sql = [NSSWF @"delete from %@ where masterkey = '%@'",[positionsTabellen oai:ii],pk];
                    SQL(sql);
                }
            }
            [self _didDelete:eo];
            countCombinedQ--;
            newSelection = [ma indexOfObject:eo];
            [ma removeObject:eo];
            if ((i+1)%50 == 0) {
                [mp release];
                mp = [NSAutoreleasePool new];
            }
        }
	[mp release];
        [self setPendingAction:pa_non];
// hinter zuletzt geloeschtes EO positionieren; nicht mehr mit _delete, weil einzelne EOs vielleicht nicht geloescht wurden aufgrund srciptRC;
        if(newSelection<0)newSelection=0;
        if(newSelection>=[ma count])newSelection=[ma count]-1;
        [self gotoRow:newSelection];
        wasDuplicate = NO;
        [self setNeedsSave:NO];
    }
}
- (void)save;
{
    NSMutableDictionary *returnDict;
    //pending Action mit pending EO ausfuehren;
    if([self save_ButtonIsDisabled])return;
    LOG_ACTION;
    if(!needsSave  || [self anzeigemodus])return;
    if([errorAssos count])return;
    [parmDict setSecureObject:selObj forKey:@"p_eo"];
    returnDict = [_APP executeScriptNamed:[NSSWF @"%@/willSave",nameForScript] datasource:self parmDict:parmDict];
    if([[returnDict ofk:@"scriptRC"] iE:@"N"])return;
    [self handlePidimage]; //filneame versorgen
    if(pendingAction == pa_upd){
        if(![self _willUpdate:selObj])return;
        if([_APP updateEO:selObj]){ //manuell immer mit Pruefungen
            [self noChanges];
            [self _selObjChanged];
            wasDuplicate = NO;
            [self _didUpdate:selObj];
            [parmDict setObject:@"update" forKey:@"p_operation"];
            [_APP executeScriptNamed:[NSSWF @"%@/didSave",nameForScript] datasource:self parmDict:parmDict];
            return;
        }
    }else{
        if(![self _willInsert:selObj])return;
        if([_APP insertEO:selObj]){
            [self noChanges];
            [self _selObjChanged];
            countCombinedQ++;
            [self _didInsert:selObj];
            wasDuplicate = NO; // muss in didInsert noch festgestellt werden koennen, um positionen zu kopieren;
            [parmDict setObject:@"insert" forKey:@"p_operation"];
            [_APP executeScriptNamed:[NSSWF @"%@/didSave",nameForScript] datasource:self parmDict:parmDict];
            return;
        }else{
            NSString *pk = [selObj primaryKey];
            if(!FILLED(pk)){
                LOGI(TRANSLATION(@"Insert fehlgeschlagen, Schluessel ist nicht gefuellt."));
            }else{
                LOGI(([NSSWF TRANSLATION(@"Insert fehlgeschlagen, Satz mit Schluessel %@ schon vorhanden"),pk]));
            }
        }
    }
}
- (NSString *)isInserting;
{
    return ((pendingAction == pa_ins)?@"J":@"N");
}
- (BOOL)ceoh_will:(NSString *)s eo:(PBEO *)eo;
{
//willInsert, willUpdate, willDelete
    NSMutableDictionary *returnDict;
    [parmDict setSecureObject:eo forKey:@"p_eo"];
    returnDict = [_APP executeScriptNamed:[NSSWF @"%@/%@",nameForScript,[s stringWithoutLastChar]] datasource:self parmDict:parmDict];
    if([[returnDict ofk:@"scriptRC"] iE:@"N"])return NO;
    return YES;
}
- (BOOL)_willInsert:(PBEO *)eo;
{
    if(![self _validate:eo])return NO;
    if(![self ceoh_will:@"willInsert:" eo:eo])return NO;
    return YES;
}
- (BOOL)_willDelete:(PBEO *)eo;
{
    if(![self ceoh_will:@"willDelete:" eo:eo])return NO;
    return YES;
}
- (BOOL)_willUpdate:(PBEO *)eo;
{
    if(![self _validate:eo])return NO;
    if(![self ceoh_will:@"willUpdate:" eo:eo])return NO;
    return YES;
}
- (void)_didCreate:(PBEO *)eo;
{
    [parmDict setSecureObject:eo forKey:@"p_eo"];
    [_APP executeScriptNamed:[NSSWF @"%@/didCreate",nameForScript] datasource:self parmDict:parmDict];
}
- (void)_didInsert:(PBEO *)eo;
{
    [parmDict setSecureObject:eo forKey:@"p_eo"];
// moduluebergreifende EO-Events
    if(wasDuplicate && [positionsTabellen count]){
        int i,j;
        for(i=0,j=[positionsTabellen count];i<j;i++){
            NSString *posen = [positionsTabellen oai:i];
            if(![[MYDD tableNamedCheap:posen] plainAttrNamed:@"__no_duplicate"]){  // damit laesst sich das mitduplizieren einzelner Positionstabellen unterdruecken
                [_APP copyPosFrom:duplicatedObj to:eo posEn:posen]; // ruft auch Script will/didCopyPos auf
            }
        }
    }
    [_APP executeScriptNamed:[NSSWF @"%@/didInsert",nameForScript] datasource:self parmDict:parmDict];
    if(masterEO)[_APP refetchEO:masterEO]; //fetched nochmal alle attr., laesst das PBEO aber als solches;
    [self setDuplicatedObj:nil];
}
- (void)_didUpdate:(PBEO *)eo;
{
    [parmDict setSecureObject:eo forKey:@"p_eo"];
// moduluebergreifende EO-Events
    [_APP executeScriptNamed:[NSSWF @"%@/didUpdate",nameForScript] datasource:self parmDict:parmDict];
    if(masterEO)[_APP refetchEO:masterEO]; //fetched nochmal alle attr., laesst das PBEO aber als solches;
}
- (void)_didDelete:(PBEO *)eo;
{
    [parmDict setSecureObject:eo forKey:@"p_eo"];
// moduluebergreifende EO-Events
    [_APP executeScriptNamed:[NSSWF @"%@/didDelete",nameForScript] datasource:self parmDict:parmDict];
    if(masterEO)[_APP refetchEO:masterEO]; //fetched nochmal alle attr., laesst das PBEO aber als solches;
}
- (void)undo;
{
    if([self undo_ButtonIsDisabled])return;
    LOG_ACTION;
    
    switch(pendingAction){
        case pa_upd:	
            [selObj undo]; //aus snapshot wieder in variablen
            [self noChanges];
            break;
        case pa_ins:	//einfach loeschen;
            [self delete];
            break;
    }
}
- (void)noChanges;
{
    [self setPendingAction:pa_non];
    [self setNeedsSave:NO];
}
- (void)empty;
{
// ma leer machen; sinnvoll, wenn ein Modul per scripting ferngesteuert wird und man einen definierten Ausgangspunkt herstellen will; z.B. um sicherzugehen, dass das Modul nicht auf einem inaktiven/stornierten selObj steht und daher anzeigemodus aktiv ist;
    [self takeObjects:nil];
    countCombinedQ = 0;
}
- (void)awake;
{
    [self setNextModul:nil];
    [_APP setCurrentComponent:self];
    [self resetErrorAssos];
}
- (void)prepareBoxesforDisplay;
{
    int i,j;
    for(i=0,j=[[self selectedBox] count];i<j;i++){
        PBWOAsso *pbas = [[self selectedBox] oai:i];
        [pbas targetToVal]; //Assos holen Values von ihren targets
    }
    for(i=0,j=[commonBox count];i<j;i++){
        PBWOAsso *pbas = [commonBox oai:i];
        [pbas targetToVal]; //Assos holen Values von ihren targets
    }
}
- (void)refreshDisplay;
{
// f. Scripts, die etwas am selObj veraendert haben; auch TV neu zeichnen
    [self _selObjChanged]; // loest Feld/Button-Steuerung aus
}
- (void)markPrepareTVDataForDisplay;
{
}
- (void)prepareDataForDisplay;
{
    [self prepareBoxesforDisplay]; // um in PBWOPosEditor besser ueberschreiben zu koennen
}
- (NSString *)tvAsString;
{
    LMAN(alles);
    int i,j,i1,j1,count=0;
//    background-color:#C0C255;
//    color: white;
    NSString *positionFieldf = @"<td bgColor=\"%@\"><a name=\"tvNewPositionField%i\" id=\"%@\" onClick=\"sbm('tvNewRowClicked%i');\" href=\"#\" onBlur=\"style.backgroundColor='%@';\" onFocus=\"style.backgroundColor='#C0C255';\">></a></td>";
// eocolor, count, assoID, count, eocolor
// style setzen tut nicht!!!
//    NSString *rowf = @"<td style=\"backgroundColor:'%@'; color:'%@';\" onClick=\"sbm('tvNewRowClicked%i');\"  onMouseOver=\"style.backgroundColor='#C0C255'; style.color='#FFFFFF';\" onmouseout=\"style.backgroundColor='%@';style.color='%@';\">";
// eocolor, fontcolor,  count, eocolor, fontcolor
    NSString *rowf = @"<td bgColor='%@' onClick=\"sbm('tvNewRowClicked%i');\"  onMouseOver=\"style.backgroundColor='#C0C255';\" onmouseout=\"style.backgroundColor='%@';\">";
// eocolor,  count, eocolor
    NSString *cellf = @"<span class=\"TVCell\" style=\"color:%@; width:%i; text-align:%@; %@\">%@&nbsp;</span>";
// fontcolor,width,left/right,strike,wodVal
    NSString *headerf = @"<span class=\"%@\" style=\"width:%i; text-align:%@;\"><a title=\"nach %@ sortieren\" href=\"#\" class=\"PBActionLinkTVHeader\" onClick=\"sbm('actionTableElement_%@');\">%@</a></span>";
// style,width, alignment, guiNameSort, dbName, guiName
    [alles addObject:@"<tr><td class=\"titleBar\" width=1%></td><td class=\"titleBar\">"];
    for(i1=0,j1=[columns count];i1<j1;i1++){
        PBWOTVCCol *column = [columns oai:i1];
        PBWOAsso *cAsso = [column cAsso];
        NSString *style;
        if(column == tvcSortCol){
            style = @"TVHeaderSorted";	// Highlighten f. Positionierspalte
        }else{
            style = @"TVHeader";
        }
        [alles addObject:[NSSWF headerf,style,[column width],[cAsso alignment],[cAsso guiName],[cAsso dbName],[column tvNewGuiNameSort]]];
    }
    [alles addObject:@"</td></tr>"];
    i = currentPage * [self pageLeng];
    j = MIN((i+[self pageLeng]),[ma count]);
    for(;i<j;i++){
        PBEO *eo = [ma oai:i];
        NSString *fontColor,*color=@"FFFFFF",*pfcolor=@"FFFFFF",*assoID;
        NSString *strike = @"";
        NSString *s = [eo eoColor];
        if(FILLED(s))pfcolor =  s;
        if(IS_CHECKED(eo)){
            color =  @"#C0C255";
            fontColor = @"#FFFFFF";
            assoID = @"target52";
        }else{
            if(FILLED(s))color =  s;
            fontColor = @"#000000";
            assoID = @"target53";
        }
        if(isInActive(eo))strike=@"text-decoration:line-through;";
        [alles addObject:@"<tr>"];
        [alles addObject:[NSSWF positionFieldf,pfcolor,count,assoID,count,pfcolor]];
// eocolor,  count, eocolor
        [alles addObject:[NSSWF rowf,color,count,color]];
        for(i1=0,j1=[columns count];i1<j1;i1++){
            PBWOTVCCol *column = [columns oai:i1];
            PBWOAsso *cAsso = [column cAsso];
            PBDDAttribute *pba = [cAsso pba];
            NSString *s=@"",*s1 = [cAsso dbName],*wodVal=@"";
            int tt = [pba targetTyp];
            if(tt==ATTVCSELOBJ){
                s = [eo vfk:s1];
            }else if(tt==ATTVCPD){
                s = [[self parmDict] ofk:s1];
            }
            if([cAsso isNI]){
                if(!FILLED(s)){
                    wodVal=GIF_1A;
                }else{
                    wodVal = [NSSWF @"%@/Images/%@_%@.gif",[_APP resourceURL],s1,s];
                }
            }else if([cAsso hasVL]){
                wodVal = [pba bezeichnungForValue:s];
            }else{
                wodVal = [cAsso formatOut:s];
            }
            if(!wodVal)wodVal = @"";
            if(![pba html]){
                wodVal = [wodVal htmlEscapedString]; // html kann invalid werden, wenn man was abschneidet
            }else{
                wodVal = [wodVal abbreviated80String]; // wg. memofeldern in tv
            }
// fontcolor,width,left/right,strike,wodVal
            [alles addObject:[NSSWF cellf,fontColor,[column width],[cAsso alignment],strike,wodVal]];
        }
        [alles addObject:@"</td>"];
        [alles addObject:@"</tr>"];
        count++;
    }
    return [alles componentsJoinedByString:@""];
}
- (BOOL)hasPidImage; /*" f. ViewPage in CMS"*/
{
    if(!selObj)return NO;
    return ([myFM fileExistsAtPath:[self pidImagePath]]);
}
- (NSString *)namedIconSrc;
{
    NSString *s;
    if(!selObj)return GIF_1A; //kein eo, kein Bild
    s = [selObj vfk:[currentAsso dbName]];
    if(!FILLED(s))return GIF_1A;
//muss einfach da sein
    return [NSSWF @"%@/Images/%@_%@.gif",[_APP resourceURL],[currentAsso dbName],s];
}
- (NSString *)tnPidImageUrl;
{
    return [NSSWF @"%@/documents/%@_tn.jpg",[_APP resourceURL],[[selObj pidimagefnJpg]stringByDeletingPathExtension]];
}
- (NSString *)pidImageUrl;
{
    return [NSSWF @"%@/documents/%@",[_APP resourceURL],[selObj pidimagefnJpg]];
}
/////////////////////////////
- (WOElement *)allSelection;
{
    int i,j;
    LMAN(oso);
    [self setSelObj:nil];
    [oso addObjectsFromArray:selectedObjects];
    
    for(i=0,j=[ma count];i<j;i++){
        SET_CHECKED([ma oai:i]);
    }
    [selectedObjects removeAllObjects];
    [selectedObjects addObjectsFromArray:ma];
    if(([selectedObjects count]==1)){
        [self setSelObj:[selectedObjects firstObject]];
    }
    if(![oso iE:selectedObjects]){ //selektion hat sich geaendert
        [self _selObjChanged];
    }
    return self;
}
- (WOElement *)multiSelOn; // in Multiselection Modus wechseln
{
    multiSelect = YES;
    return self;
}
- (WOElement *)multiSelOff; // Multiselection Modus beenden
{
    multiSelect = NO;
    return self;
}
- (WOElement *)multiSelToggle; // Multiselection Modus umschalten
{
    multiSelect = !multiSelect;
    return self;
}
- (NSString *)multiSelString;
{
    if(multiSelect)return @"M";
    return @"1";
}
- (WOElement *)editLine:(int)line columnName:(NSString *)columnName;
{
    int absRowIndex = currentPage * [self pageLeng] + line;
    if(absRowIndex >= [ma count])absRowIndex = [ma count]-1;
    if(absRowIndex < 0)return self;
    if(multiSelect){
        // Satz den selectedObjects zufuegen oder rausnehmen
        PBEO *eo = [ma oai:absRowIndex];
        if(IS_CHECKED(eo)){
            [selectedObjects removeObject:eo];
            SET_UNCHECKED(eo);
        }else{
            [selectedObjects addObject:eo];
            SET_CHECKED(eo);
        }
        [self gatherSelectedObjects];
    }else{
        isMaximizedDetail = YES;
        [self gotoRow:absRowIndex];
    }
    return self;
}
- (WOElement *)pageBack;
{
    if(currentPage > 0){
        currentPage--;
    }else{
        if(maOffset){
            [self offsetZurueck];
            currentPage = [self numOfPages]-1;
        }
    }
    isMaximized=YES;
    return self;
}
- (WOElement *)pageForward;
{
    if(currentPage < [self numOfPages]-1){
        currentPage++;
    }else{
        if([ma count] == fetchLimit){
            [self offsetWeiter];
            if([ma count]){
                currentPage = 0;
            }else{
                [self offsetZurueck];
            }
        }
    }
    isMaximized=YES;
    return self;
}
/////////////////////////////
//parameter, die von wod geschrieben werden
/////////////////////////////
- (NSArray *)currentBox;
{
    return [boxDict ofk:currentBoxName];
}
- (BOOL)mayGotoBoxTitle;
{
    return ![currentBoxName iE:selectedBoxName];
}
- (void)df;
{
//datenfreigabe und default-action der form, wenn mit javascript form.submit() aufgerufen wird
//bei klick auf einen boxname wird ein js ausgefuehrt, das den boxname setzt in der der form in submitter und die form submitted;
//damit werden die eingegebenen werte uebernommen, wenn die box verlassen wird
    NSString *submitter = [[[self context] request] formValueForKey:@"submitter"];
    NSString *clickedColumnName = [[[self context] request] formValueForKey:@"clickedColumnName"];
    if([_APP log_changes])LOGS(([NSSWF @"submitter=%@",submitter]));
    if([submitter hasSecurePrefix:@"action_gotoCurrentLaunchedModule"]){
        // Klick auf ein Register in den geoeffneten Modulen
        [self gotoCurrentLaunchedModuleNr:[[submitter substringFromIndex:[@"action_gotoCurrentLaunchedModule" length]]intValue]];
        return;
    }
    if([submitter hasSecurePrefix:@"action_gotoPositionen_"]){
        // Positionseditor aufrufen
        if(![self selObj]){
            LOGI(TRANSLATION(@"bitte genau einen Satz auswaehlen"));
            return;
        }else{
            PBWOPosEditor *e;
            if([[callingModul name]iE:@"PBWOPosEditor"]){ // kleiner Hack, um mehrfache PosEditoren haben zu koennen
                e = MODUL(@"PBWOPosEditor1"); // muss als Modul angelegt werden, identisch wie PBWOPosEditor
            }else{
                e = MODUL(@"PBWOPosEditor");
            }
            if(!e){
                LOGI(TRANSLATION(@"PBWOPosEditor nicht bekommen"));
                return;
            }
            if(![self paNon]){
                [self save];
            }
            if(![self paNon]){
                LOGI(TRANSLATION(@"bitte zuerst vervollstaendigen und sichern"));
                return;
            }
            [e setCallingModul:self];
            [e setMyTable:[MYDD tableNamedCheap:[submitter substringFromIndex:[@"action_gotoPositionen_" length]]] andMasterEO:[self selObj]];
            [self bringToFront:e];
// noch anzeige modus setzen...
            return;
        }
    }
// Portlet-Actions durchrouten; Name des Portlets ist hinten angehaengt
    if([submitter hasSecurePrefix:@"action_portletRefresh_"]){
        [[portletDict ofk:[submitter substringFromIndex:[@"action_portletRefresh_" length]]] refresh];
        return;
    }
    if([submitter hasSecurePrefix:@"action_portlet_currentLine"]){
        PBWOPortlet *po = [portletDict ofk:[submitter substringFromIndex:[@"action_portlet_currentLineXActed_" length]]];
        SEL sel = SECURE_SELECTOR_FROM_STRING([[submitter substringFromIndex:[@"action_portlet_" length]]substringToIndex:[@"currentLineXActed" length]]);
        if(sel)[po performSelector:sel];
        return;
    }
    if([submitter hasSecurePrefix:@"action_script_"]){
        // direkt das Script aufrufen; muss im Modul-Verzeichnis liegen; geht ohne Berechtigung, ohne Attribut-Button;
        [_APP executeScriptNamed:[NSSWF @"%@/%@",nameForScript,[submitter substringFromIndex:[@"action_script_" length]]] datasource:self parmDict:parmDict];
        return;
    }
    if([submitter hasSecurePrefix:@"action_"]){
        // PBActionLinks verwenden dies
        SEL sel = SECURE_SELECTOR_FROM_STRING([submitter substringFromIndex:7]);
        if(sel)[self performSelector:sel];
        return;
    }
    if([submitter hasSecurePrefix:@"attributeButton_"]){
        // emuliert den Klick auf den Button;
        [self attributeButtonActed:[submitter substringFromIndex:[@"attributeButton_" length]]];
        return;
    }
    if([submitter hasSecurePrefix:@"confirm_"]){  // Actions in Confirm-Mode; nicht die Ja/Nein Buttons
        [_APP continueScript];
    }
    if([submitter hasSecurePrefix:@"gotoBox_"]){
        NSString *s = [submitter substringFromIndex:8];
        [self setSelectedBoxName:s];
        return;
    }
    if([submitter hasSecurePrefix:@"tvNewRowClicked"] && [self paNon]){
        int index = [[submitter substringFromIndex:[@"tvNewRowClicked" length]]intValue];
        if([self paNon])[self editLine:index columnName:clickedColumnName];
        return;
    }
    if([submitter hasSecurePrefix:@"actionTableElement_"]){
        // sortierung umstellen;
        // column fuer den dbName ermitteln
        NSString *dbName = [submitter substringFromIndex:[@"actionTableElement_" length]];
        int i,j;
        for(i=0,j=[columns count];i<j;i++){
            PBWOTVCCol *column = [columns oai:i];
            if([[column dbName]iE:dbName]){
                if([[[column cAsso]pba]isDB]){
                    if([column tvNewSortMode]==SORTMODE_A){ // -> D
                        [self setSoseq:[NSSWF @"%@:d",dbName]]; // konfiguriert die Spalten neu, macht soa
                    }else{
                        [self setSoseq:dbName];
                    }
                    [self saveSoseq];
                    tvNewRowOffset = 0;
                    currentPage = 0;
                    maOffset = 0;
                    [self neuSuchen]; // immer serverside sort
                }
            }
        }
    }
}
- (void)takeString:(NSString *)s;
{
// bei Uebernahme aus Kalender oder der primary Key eines EO aus einem Lookup
    PBDDAttribute *pba = [waitingForName pba];
    PBEO *targetObject;
    if(!pba)return; // wir wollen nix haben
    if(!s || ![waitingForName inputAllowed]){
        [self setWaitingForName:nil];
        return;
    }
    if([pba targetTyp]==ATTVCPD){
        targetObject = (PBEO *)parmDict;
    }else{
        targetObject = selObj;
    }
    if(targetObject){
        [targetObject tvfk(s,[pba dbName])];
        [self didValToTargetPba:pba];
        [self setExternalFieldToFocusOn:waitingForName];
        // [self bringToFront:self]; //falls das callingmodul das vergessen hat zu tun
    }
    [self setWaitingForName:nil];
}
- (NSString *)namedIconAlt;
{
    NSString *s = [currentAsso wodVal];
    if(!s)s = EON;
    return [NSSWF @"%@ = %@",[currentAsso guiName],s];
}
- (NSArray *)selectedBox;
{
    //Assos der selectedBox
    return [boxDict ofk:selectedBoxName];
}
/////////////////////////////
//parameter, die von wod gelesen werden
/////////////////////////////
- (int)pageLeng;
{
    int pl;
    pl=[[parmDict ofk:@"pageLeng"]intValue]; // in didBuildUp Script zu konfigurieren
    if(pl)return pl;
    if(isMaximizedDetail){
        pl = [[[_APP configDict]ofk:@"rowsonpage"]intValue];
        if(!pl)pl=10;
    }else{
        pl = [[[_APP configDict]ofk:@"rowsonpagel"]intValue];
        if(!pl)pl=20;
    }
    return pl;
}
- (int)numOfPages;
{
    return ([ma count]+[self pageLeng]-1)/[self pageLeng];
}
- (int)colCount;
{
    return [columns count];
}
- (BOOL)hasTV;
{
    return ( [self colCount]>0);
}
- (BOOL)hasPages;
{
    return [self numOfPages]>1;
}
- (BOOL)mayPageBack;
{
    return currentPage > 0 || maOffset > 0;
}
- (BOOL)mayNotPageBack;
{
    return ![self mayPageBack];
}
- (BOOL)mayPageForward;
{
    return currentPage < [self numOfPages]-1 || [ma count]==fetchLimit;
}
- (BOOL)mayNotPageForward;
{
    return ![self mayPageForward];
}
- (void)gatherSelectedObjects;
{
    [self gatherSelectedObjectsAndGoto:YES];
}
- (void)gatherSelectedObjectsAndGoto:(BOOL)gotoSelObj;
{
//aufgrund von isCheckedPBEO das selObj und die selectedObjects in richtiger Reihenfolge bestimmen;
//dabei feststellen, ob sich selektion geaendert hat
//gotoSelObj steuert, ob auf Seite des selObj positioniert wird
    int i,j;
    LMAN(oso);
    [self setSelObj:nil];
    [oso addObjectsFromArray:selectedObjects];
    [selectedObjects removeAllObjects];
    for(i=0,j=[ma count];i<j;i++){
        PBEO *eo = [ma oai:i];
        if(IS_CHECKED(eo)){
            [selectedObjects addObject:eo];
            selRow = i;
        }
    }
    if(([selectedObjects count]==1)){
        [self setSelObj:[selectedObjects firstObject]];
        if(gotoSelObj)currentPage = selRow / [self pageLeng];
    }
    if((pendingAction == pa_ins) || ![oso iE:selectedObjects]){ //selektion hat sich geaendert
        [self _selObjChanged];
    }
}
- (void)appendToResponse:(WOResponse *)aResponse inContext:(WOContext*)aContext
{
    [self prepareDataForDisplay];
 //   LOGS(([NSSWF @"tvNewRowOffset=%i currentPage=%i numOfPages=%i",tvNewRowOffset,currentPage,[self numOfPages]]));
    fieldsInSelectedRegisterIndex=0;
    if(isConfigMode)[lifFieldDict removeAllObjects];
    [super appendToResponse:aResponse inContext:aContext];
    if([_APP log_changes])LOG(@"------- [changedInRequest removeAllObjects] -----");
    [changedInRequest removeAllObjects];
}
- (void)takeObjects:(NSArray *)someObjects;
{
//fuellt das ma neu, mit EOs, die z.B. gefetched wurden
    
    if(![self paNon]){
        LOGI(([NSSWF TRANSLATION(@"%@ hat ungespeicherte Aenderungen und konnte daher die Objekte nicht annehmen."),guiName]));
        return;
    }
    [ma removeAllObjects];
    [ma addObjectsFromArray:someObjects];
// vor dem sortieren aufrufen, damit script die Sortierung noch beeinflussen kann
    [_APP executeScriptNamed:[NSSWF @"%@/didTakeObjects",nameForScript] datasource:self parmDict:parmDict];
    [self positionTo:TOP];
    [[stateArray lastObject]updateStateFrom:self];
}
- (void)positionTo:(int)posMode;
{
    int i = selRow;
    switch(posMode){
        case TOP:
            [self gotoRow:0];
            break;
        case KEEP:
            [self gotoRow:i];
            break;
        case BOT:
            [self gotoRow:[ma count]-1];
            break;
    }
}
- (void)gotoObject:o;
{
//auf ein best. Objekt positionieren, von dem man meint, es sei im ma
    int i;
    if(!o)return;
    i = [ma indexOfObject:o];
    if(i != NSNotFound)[self gotoRow:i];
}
- (void)_delete;
{
// alle selectedObjects aus ma und aus selectedObjects raus
// auf erstes eo nach dem letzten geloeschten positionieren
    if([selectedObjects count]){
        int newSelection = [ma indexOfObject:[selectedObjects lastObject]];
        PBEO *newEO=nil;
        if(newSelection != NSNotFound){
            newSelection++;
            if(newSelection < [ma count])newEO = [[ma oai:newSelection]retain];
        }
        [ma removeObjectsInArray:selectedObjects];
        if(newEO){
            newSelection = [ma indexOfObject:newEO];
            [newEO release];
        }else{
            newSelection=[ma count]-1;
        }
        if(newSelection<0)newSelection=0;
        if(newSelection>=[ma count])newSelection=[ma count]-1;
        [self gotoRow:newSelection];
    }
}
- (NSMutableArray *)errorAssos;
{
    return errorAssos;
}
- (int)selRow;
{
    return selRow;
}
- (void)executeDidTakeValuesFromRequest;
{
// in diesem Event koennen alle Editierungen abschliessend begutachtet werden
// oldValues des selObj
    [parmDict setSecureObject:selObj forKey:@"p_eo"];
    [_APP executeScriptNamed:[NSSWF @"%@/didTakeValuesFromRequest",nameForScript] datasource:self parmDict:parmDict];
    [parmDict removeObjectForKey:@"p_eo"];
}
- (void)takeValuesFromRequest:(WORequest *)aRequest inContext:(WOContext *)aContext;
{
    [super takeValuesFromRequest:aRequest inContext:aContext];
    [self executeDidTakeValuesFromRequest];
}
- (void)didValToTargetPba:(PBDDAttribute *)pba;
{
    NSString *value=nil,*dbName;
    if(!pba)return;
    dbName = [pba dbName];
    if([pba targetTyp]==ATTVCSELOBJ){
        if(selObj){
            value = [selObj vfk:dbName];
            [self aValueChanged];
        }
    }else{
        value = [parmDict ofk:dbName];
    }
    if(!value)value = EON;
    [parmDict setSecureObject:selObj forKey:@"p_eo"];
    [changedInRequest setObject:value forKey:dbName]; // sammeln f. didTakeValuesFromRequest
    [parmDict setObject:dbName forKey:@"p_didValToTargetName"];
    [parmDict setObject:value forKey:@"p_didValToTargetValue"];
    [_APP executeScriptNamed:[NSSWF @"%@/didValToTarget",nameForScript] datasource:self parmDict:parmDict];
    [parmDict removeObjectForKey:@"p_didValToTargetName"];
    [parmDict removeObjectForKey:@"p_didValToTargetValue"];
    [parmDict removeObjectForKey:@"p_eo"];
// f. Debugging, wenn ein EO ploetzlich meint, es sei geaendert worden
    if([_APP log_changes] && ([pba targetTyp]==ATTVCSELOBJ) && selObj && [selObj isKindOfClass:[PBEO class]])LOGS(([NSSWF @"Feld:%@ (%@)\nneu:>%@<\nalt:>%@<\nneuHex:>%@<\naltHex:>%@<",[pba guiName],dbName,value,[[selObj oldValues]ofk:dbName],[value hexFormat],[[[selObj oldValues]ofk:dbName]hexFormat]]));
}
- (void)didSetValueForKey:(NSString *)dbName;
{
// aufzurufen, wenn man an der Asso vorbei von aussen einen Wert gesetzt hat; z.B. in scripts;
// geht auch, wenn es gar keine Asso gibt
// ein PBDDAttribute muss es allerdings geben
    if(!dbName)return;
    [self didValToTargetPba:[myTable plainAttrNamed:dbName]];
}
- (void)handlePidimage;
{
// Filename eines evt. gestzten Pid-Image Dokuments beschaffen beim Speichern
    if([myTable hasPidimage]){
        NSString *s = [selObj vfk:@"pidimage"];
        if(FILLED(s)){
            PBEO *doc = getEOPkValue(@"document",s);
            if(doc){
                [selObj tvfk([doc vfk:@"filename"],@"pidimagefn")];
                [selObj setPidimagefnJpg:[doc vfk:@"filename"]];
            }else{
                [selObj tvfk(EON,@"pidimagefn")];
                [selObj setPidimagefnJpg:@"1a.jpg"];
            }
        }else{
            [selObj tvfk(EON,@"pidimagefn")];
            [selObj setPidimagefnJpg:@"1a.jpg"];
        }
    }
}
- (NSMutableArray *)selectedObjects;
{
    return selectedObjects;
}
- (NSString *)objCountS;
{
    int i;
    if(![self paNon])return EON;
    if(selObj)return [NSSWF TRANSLATION(@"%i. von %i / %i"),(maOffset + selRow)+1,countCombinedQ,[stateArray count]];
    if((i=[selectedObjects count]))return [NSSWF @"%i markiert von %i / %i",i,countCombinedQ,[stateArray count]];
    return NSS(countCombinedQ);
}
- (NSString *)fieldIDToFocusOn;
{
    PBWOAsso *pbas;
    int i,j;
    NSArray *a = [self selectedBox];
    if([_SESSION dialogMode]){
        return @"confirm_ja";
    }
    if(![self isMaximizedDetail])return @"target49";
    if([self isConfigMode]){
        if([self isConfigModeDetail]){
            if([[parmDict ofk:@"p_lastAction"]iE:@"removeField"])return @"fieldsInSelectedRegister";
            if([[parmDict ofk:@"p_lastAction"]iE:@"addField"])return @"fieldsOrControls";
            if([[parmDict ofk:@"p_lastAction"]iE:@"selectFieldForEdit"])return @"selectedFieldTextField";
        }
        return nil;
    }
    if([errorAssos count])return [[errorAssos firstObject]assoID];
    if([externalFieldToFocusOn isKindOfClass:[PBWOAsso class]]){
        return [externalFieldToFocusOn assoID];
    }
    if(waitingForName)return [waitingForName assoID];
    for(i=0,j=[a count];i<j;i++){
        pbas = [a oai:i];
        if([pbas inputAllowed]){
            return [pbas assoID];
        }
    }
    return @"target49";
}
- (BOOL)isMaximized;
{
// TV
    return isMaximized;
}
- (WOElement *)maximize;
{
// TV
    isMaximized = YES;
    return self;
}
- (WOElement *)minimize;
{
// TV
    isMaximized = NO;
    return self;
}
- (BOOL)isMaximizedDetail;
{
    if([self needsSave])return YES;
    return isMaximizedDetail;
}
- (WOElement *)maximizeDetail;
{
    isMaximizedDetail = YES;
    currentPage *= 2;
    return self;
}
- (WOElement *)minimizeDetail;
{
    if([self needsSave])return nil;
    isMaximizedDetail = NO;
    currentPage /= 2;
    return self;
}
- (BOOL)mayNextBox;
{
    if([boxNameArray count]<=1)return NO;
    return ![selectedBoxName iE:[boxNameArray lastObject]];
}
- (BOOL)mayPrevBox;
{
    if([boxNameArray count]<=1)return NO;
    return ![selectedBoxName iE:[boxNameArray firstObject]];
}
- (BOOL)mayNotPrevBox;
{
    return ![self mayPrevBox];
}
- (BOOL)mayNotNextBox;
{
    return ![self mayNextBox];
}
- (WOElement *)nextBox;
{
    int i;
    if(![self mayNextBox])return self;
    i = [boxNameArray indexOfObject:selectedBoxName];
    if(NSNotFound == i)return self;
    i++;
    if(i>=[boxNameArray count])return self;
    [self setSelectedBoxName:[boxNameArray oai:i]];
    return self;
}
- (void)gotoFirstBox;
{
    [self setSelectedBoxName:[boxNameArray firstObject]];
}
- (WOElement *)prevBox;
{
    int i;
    if(![self mayPrevBox])return self;
    i = [boxNameArray indexOfObject:selectedBoxName];
    if(NSNotFound == i)return self;
    i--;
    if(i<0)return self;
    [self setSelectedBoxName:[boxNameArray oai:i]];
    return self;
}
- (BOOL)hasSelObj;
{
    return selObj != nil;
}
//-------------------------------------------------------------------
- (NSString *)pidImagePath;
{
    return [NSSWF @"%@/tables/%@/%@.jpg",RESOURCEPATH,[selObj entityName],[selObj primaryKey]];
}
- (NSString *)pidImageTNPath;
{
    return [NSSWF @"%@/tables/%@/%@_tn.jpg",RESOURCEPATH,[selObj entityName],[selObj primaryKey]];
}
- (BOOL)_validate:(PBEO *)eo;
{
    int i,j;
    BOOL rc = YES;
    NSArray *assos = fassos;
    if([self paNon])return YES;
    for(i=0,j=[assos count];i<j;i++){
        PBWOAsso *pbas = [assos oai:i];
        NSString *dbName = [pbas dbName];
        PBDDAttribute *pba = [pbas pba];
        int dt;
        NSString *s;
        if(![pbas inputAllowed])continue; //user kann sowieso nichts aendern
        if(!(pendingAction == pa_ins) && ![[eo oldValues] ofk:dbName])continue; // update u. Feld nicht geaendert
        if([[pbas pba]targetTyp]==ATTVCSELOBJ){
            s = [eo vfk:dbName];
        }else if([pba targetTyp]==ATTVCPD){
            s = [parmDict ofk:dbName];
        }else{
            continue;
        }
        if([pbas isMandatory]){
            dt = [pbas dataTyp];
            if(((dt == DT_FLOAT || dt == DT_MONEY || dt == DT_INT) && [s doubleValue]==0.0) || !FILLED(s)){
                LOGI(([NSSWF TRANSLATION(@"%@ ist ein Pflichtfeld."),[pbas guiName]]));
                [pbas markError];
                rc = NO;
                continue;
            }
        }
        if(pba && [pba isFK]){
            PBDDTable *t;
            PBEO *feo;
            NSString	*fpk;
            if(!(t = [pba relationTable]))continue;
            fpk = [t primaryKeyName];
            if(!FILLED(s))continue;	//gar nicht gefuellt
            if([[t primaryKeyAttr]dataTyp]==DT_INT && ![s intValue])continue; //Relation auf integer-Key und es steht 0 drin
            if(!(feo = getEOPkValue([t dbName],s))){
                LOGI(([NSSWF TRANSLATION(@"%@ %@ ist nicht vorhanden."),[t guiName],s]));
                [pbas markError];
                rc = NO;
                continue;
            }
            if(isInActive(feo)){
// LOGS([[feo values]description]);
                LOGI(([NSSWF TRANSLATION(@"%@ %@ nicht aktiv"),[t guiName],s]));
                [pbas markError];
                rc = NO;
                continue;
            }
        }
    }
    return rc;
}
- (WOElement *)gotoConfigModeListe;
{
    configMode = CONFIGMODE_Liste;
    return self;
}
//-------------------------------------------------------------------
// LIF
ACCESSm(lifEditArea,setLifEditArea);
ACCESSm(lastLifPath,setLastLifPath);
//-------------------------------------------------------------------
// TV
ACCESSm(tvNewSearchInSortCol,setTvNewSearchInSortCol);
- (void)setTvNewRowOffsetUI:(NSString *)s;
{
// UI ist immer 1 groesser, damit es bei 1 anfaengt
    [self setTvNewRowOffset:s];
    tvNewRowOffset--;
    if(tvNewRowOffset<0)tvNewRowOffset=0;
}
- (int)tvNewRowOffsetUI;
{
    return [self tvNewRowOffset] +1;
}
- (void)setTvNewRowOffset:(NSString *)s;
{
    if(!s){
        tvNewRowOffset = 0;
    }else{
        if([s hasSecurePrefix:@"+"]){
            tvNewRowOffset += [[s substringFromIndex:1]intValue];
            return;
        }
        if([s hasSecurePrefix:@"-"]){
            tvNewRowOffset -= [[s substringFromIndex:1]intValue];
            if(tvNewRowOffset<0)tvNewRowOffset=0;
            return;
        }
        tvNewRowOffset = [s intValue];
    }
}
- (int)tvNewRowOffset;
{
    return  maOffset + (currentPage * [self pageLeng]);
}
- (void)tvNewRowOffsetActed;
{
//zu dem satz springen; dort seite beginnen
    BOOL maOffsetChanged = NO;
    if(needsSave || ![self paNon]){
        tvNewRowOffset = maOffset + (currentPage * [self pageLeng]);
        return;
    }
    if(tvNewRowOffset>countCombinedQ)tvNewRowOffset=countCombinedQ - [self pageLeng]; //obere grenze
    if(tvNewRowOffset<0)tvNewRowOffset=0;
// offset innerhalb countCombinedQ; muss noch richtig gemacht werden
// feststellen, ob innerhalb der gefetchten saetze
    if(!((tvNewRowOffset >= maOffset) && (tvNewRowOffset < (maOffset + fetchLimit)))){
// neues maOffset bestimmen und fetchen
        maOffset = (int)(tvNewRowOffset / fetchLimit) * fetchLimit;
        [self neuSuchen]; //mit lastCombinedQ
        maOffsetChanged = YES;
    }
    currentPage = (tvNewRowOffset - maOffset) / [self pageLeng];
    tvNewRowOffset = maOffset + (currentPage * [self pageLeng]);
    if(![selectedObjects count] || maOffsetChanged)[self editLine:0 columnName:nil]; //immer auf erste zeile der seite, wenn nix markiert
}
- (void)tvNewSearchInSortColActed;
{
// erstmal versuchen innerhalb ma zu positionieren
// schlaegt das fehl, neu fetchen
// wenn Spalte aufsteigend: den Satz, dessen Wert in der Sortierspalte >= dem Suchwert ist
// wenn Spalte absteigend: den Satz, dessen Wert in der Sortierspalte <= dem Suchwert ist
// numerisch, Datum, string
// eigentlich sollte man hier binary-search machen
    int i,j,sm=0,dt;
    NSString *dbName;
    double compValNum=0.0;
    long compValDate=0;
    NSString *compValChar=nil,*compValSQL,*sql;
    double eoValNum=0.0;
    long eoValDate=0;
    NSString *eoValChar;
    BOOL hasVL;
    BOOL found;
    PBDate *pbd;
    if(![self paNon])return;
    if(!tvcSortCol)return; // irgendwie keine sortierspalte
    dbName = [[tvcSortCol cAsso]dbName];
    dt = [[tvcSortCol cAsso]dataTyp];
    hasVL = [[tvcSortCol cAsso]hasVL];
    sm = [tvcSortCol tvNewSortMode];
    if(!tvNewSearchInSortCol)[self setTvNewSearchInSortCol:@""];
    if(hasVL){
        compValChar = [tvNewSearchInSortCol lowercaseString];
    }else{
        if(dt == DT_MONEY || dt == DT_INT || dt == DT_FLOAT){
            compValNum = [tvNewSearchInSortCol doubleValue];
        }else if(dt == DT_DATE || dt == DT_DATETIME){
            pbd = [PBDate dateWithFreeString:tvNewSearchInSortCol];
            if(!pbd){
                LOGI(TRANSLATION(@"kein gueltiges Datum"));
                return;
            }
            [self setTvNewSearchInSortCol:[pbd dateAsUIString]];
            compValDate = [pbd dateAsLong];
        }else{
            compValChar = [tvNewSearchInSortCol lowercaseString];
        }
    }
    found = NO;
    for(i=0,j=[ma count];i<j;i++){
        PBEO *eo = [ma oai:i];
        NSString *eoVal = [eo vfk:dbName];
        if(dt == DT_MONEY || dt == DT_INT || dt == DT_FLOAT){
            eoValNum = [eoVal doubleValue];
            if((sm == SORTMODE_A && (eoValNum >= compValNum)) || (sm == SORTMODE_D && (eoValNum <= compValNum)))found=YES;
        }else if(dt == DT_DATE || dt == DT_DATETIME){
            eoValDate = [[PBDate dateWithDBString:eoVal] dateAsLong];
            if((sm == SORTMODE_A && (eoValDate >= compValDate)) || (sm == SORTMODE_D && (eoValDate <= compValDate)))found=YES;
        }else{
            NSComparisonResult cr;
            eoValChar = [eoVal lowercaseString];
            cr = [eoValChar compare:compValChar];
            if((sm == SORTMODE_A && (cr != NSOrderedAscending)) || (sm == SORTMODE_D && (cr != NSOrderedDescending)))found=YES;
        }
        if(found)break;
    }
    if(!found || (maOffset > 0 && i<=1)){
// nicht gefunden bzw. aufsatzpunkt liegt vor maOffset: fetchen;
        NSString *wc;
        if(hasVL){
// den key zur Bez finden
            compValSQL = [[[tvcSortCol cAsso]pba] valueForBezeichnung:tvNewSearchInSortCol];
        }else{
            if(dt == DT_MONEY || dt == DT_INT || dt == DT_FLOAT){
                compValSQL = tvNewSearchInSortCol;
            }else if(dt == DT_DATE || dt == DT_DATETIME){
                compValSQL = NSS(compValDate);
            }else{
                compValSQL = compValChar;
            }
        }
        wc = [lastCombinedQ string]; //bei letzter Suche mit test=NO gesetzt
        if(!wc)wc=@"";
        if(FILLED(wc))wc=[wc stringByAppendingString:@" and "];
        sql = [NSSWF @"select count(*) from %@ where %@ %@ %@ '%@'",[myTable dbName],wc,dbName,((sm == SORTMODE_A)?@"<":@">"),compValSQL];
        tvNewRowOffset = [[_APP getSingleValueAsResultFrom:sql]intValue];
    }else{
        tvNewRowOffset = maOffset + i;
    }
    [self tvNewRowOffsetActed];
}
- (BOOL)showTV;
{
    return [self paNon];
}
- (void)gotoRow:(int)r;
{
// absolut in ma
    int i,j;
//    LOGS(([NSSWF @"r=%i ma.count=%i",r,[ma count]]));
    for(i=0,j=[ma count];i<j;i++){
        SET_UNCHECKED([ma oai:i]);
    }
    if([ma count]){
        if(r>=[ma count])r=[ma count]-1;
        if(r<0)r=0;
        SET_CHECKED([ma oai:r]);
    }
    [self gatherSelectedObjects];
}
- (BOOL)mayPrevRow;
{
    return ([self paNon]) && [ma count] && (selRow > 0 || maOffset);
}
- (BOOL)mayNextRow;
{
    return ([self paNon]) && [ma count] && (selRow < [ma count]-1 || [ma count]==fetchLimit);
}
- (BOOL)mayNotNextRow;
{
    return ![self mayNextRow];
}
- (WOElement *)nextRow;
{
    if(![self mayNextRow])return self;
    if(selRow == [ma count]-1 && [ma count]==fetchLimit){
        [self offsetWeiter];
        if([ma count]){
            [self gotoRow:0];
        }else{
            [self offsetZurueck];
            [self gotoRow:selRow];
        }
    }else{
        [self gotoRow:selRow+1];
    }
    return self;
}
- (WOElement *)prevRow;
{
    if(![self mayPrevRow])return self;
    if(!selRow && maOffset){
        [self offsetZurueck];
        [self gotoRow:[ma count]-1];
    }else{
        [self gotoRow:selRow-1];
    }
    return self;
}
- (BOOL)mayNotPrevRow;
{
    return ![self mayPrevRow];
}
- (int)pageLengOrLess;
{
    int i = [ma count];
    int j = [self pageLeng];
    int k = (currentPage+1) * j;
    if(i < k)i = i%j;
    if(j < i)i= j;
    return i; //nur notwendige Zeilen zeichnen
}
- (void)copyLif;
{
    [self saveLif:lifDict path:@"/tmp/lif_pasteboard.txt"];
}
- (void)pasteLif;
{
    [self loadLif:@"/tmp/lif_pasteboard.txt"];
    [self redrawAfterLeaveConfig];
    [self saveLif];
}
@end
//-------------------------------------------------------------------
@implementation PBWOViewer
- (BOOL)anzeigemodus;
{
   return YES;
}
@end
Foto