Wiki Aventurica:Robots/WAbotTK ein GUI für die Robotskripte

aus Wiki Aventurica, dem DSA-Fanprojekt
Wechseln zu: Navigation, Suche

Warum?[Bearbeiten]

  • Weil es mit einem GUI viel einfacher und schöner ist, habe ich mit der Programmierung eines solchen begonnen: Siehe WAbotTK
    • allerdings verlangen die meisten Skripte bisher einen Aufruf mit Parametern, das müsste entsprechend im GUI mit Radiobuttons und Checkboxen berücksichtigt werden, teilweise können die alten Skripte aber auch direkt vom GUI aus aufgerufen werden

Alternativ kann ein GUI in Form des WAbotTK benutzt werden.

Interessant ist momentan im GUI das nur dort eingebaute Multiuploadskript.

  • Das GUI dient aber auch als Wiki-Editor mit Syntaxhighlightning, ein paar netten Features wie Mediawikifehler beheben, automatischer Ankündigung von Roboteinsätzen, etc.
  • Belohnungen für Abenteuer kann automatisch ausgelesen und in eine Tabelle umgewandelt werden
  • automatisierte Wikifizierung von Artikeln ist möglich

Beschreibung[Bearbeiten]

Siehe auch: Hilfe:Robots


Hier soll die Diskussion und Veröffentlichung eines GUI (=grafische Benutzerschnittstelle) stattfinden, welches die einzelnen Robotskripte steuern kann.

Es basiert auf der Datei gui.py aus dem PyWikipediaBot-Paket. Im Moment sind noch wenige Funktionen eingebaut. Immerhin funktionieren die folgenden Dinge:

  • es kann in einem Fensterbereich Text wie in einem Texteditor eingegeben werden (wie im Browser)
  • Text kann aus dem Wiki abgerufen werden und bearbeitet werden
  • mit einem Knopfdruck kann ein Syntax-Highlightning eingeschalten werden (besser wie im Browser)
  • der Text aus dem Editor kann ins Wiki hochgeladen werden
  • es kann Text aus einer Textdatei geladen und in einer gespeichert werden (mit richtiger UTF-8 Enkodierung)
  • es gibt einen Korrekturbefehl, um einen Fehler im Mediawiki-Programm bei der Erstellung von Tabellen zu beheben
  • Enkodierungsfehler (Ã ¤ Ã „ Ã ¶ Ã – Ã ¼ Ã Å“ Ã Å )können automatisch behoben und in HTML bzw. Wiki-Syntax umgewandelt werden
  • es gibt eine Suchfunktion, die im ganzen Editor jeden Treffer gleichzeitig markiert
  • Cut/Copy/Paste ist leider noch etwas buggy
  • bei der Kommunikation mit dem Wiki werden Reaktionen separat angezeigt
  • Es wird automatisch das Robotlog auf Wiki Aventurica:Roboteinsatz Logfile gelesen und mit aktueller Uhrzeit aktualisiert und kann vor dem Hochladen im Editor überarbeitet werden
  • es enthält einen Multi-Uplaoder: damit kann eine Textdatei in einem speziellen Format gelesen werden, die dann jede darin enthaltene Seite hochlädt (damit wurden inzwischen mehr als 500 Seiten hochgeladen, siehe Abenteuerliste)
  • es können einige Skripte aus dem Robotpaket per Menü aufgerufen werden (allerdings muss die Eingabe noch wie bisher in der Kommandobox erfolgen, siehe TODO)
  • bel2tab wurde eingebaut - kann als Beispiel für die Integration anderer Skripte gelten
  • Als Clou enthält der WAbotTK eine automatische Abfrage, ob auch tatsächlich die erforderlichen Anpassungen vorgenommen wurden, um überhaupt funktionieren zu können. Damit müsste es eigentlich fast idiotensicher möglich sein, das Skript zum Laufen zu bringen.

Todo:[Bearbeiten]

  • Listboxes statt Eingabefelder (MRU-Listen)
  • Variablen mit pickle speichern und beim Starten auslesen
  • sys.stdout / sys.sterr umleiten, um self.guiPrint auch per print zugänglich zu machen
  • sys.stdin müsste dann irgendwie passend abgefragt werden...
  • Betriebssystemerkennung für den Aufruf der Kommandozeile je nach Mac/Linux/win32
  • Loggen in Datei statt nur in die Nachrichtenbox
  • Encoding je nach OS durchführen, im Moment stark aus der Blickrichtung von Windows/cp1252
  • beim Multiuploadskript Abfrage und Zeit zur Bearbeitung lassen, eventuell mit Timeout
  • Viele Skripte aus dem Botpaket sind nicht dafür gedacht, mit Parametern extern aufgerufen zu werden, was nötig wäre, damit es in ein GUI integriert werden kann. Das Thema habe ich unter dem Stichwort Wiki Aventurica:Robots/OOPisierung von Skripten versucht aufzugreifen. Wenn man die Skripte selbst entsprechend anpasst, dann geht es natürlich.
  • eine Funktion, um markierten Text in Wiki-Spalten (z.B. 2 oder 3) einbetten zu können (zum Erleichtern zahlreiche momentan noch einspaltig aufgeführten Listen)

Bekannte Fehler[Bearbeiten]

  • Sofern die Standardencodierung auf UTF-8 statt auf ASCII gesetzt ist, gibt es kaum noch UnicodeEndoceErrors mehr, ansonsten natürlich schon
    • Obsolet(?):Teilweise kann das Problem mit Stringname.decode("CP1252") behoben werden, leider nicht immer
  • Fehler (try ... except) sollten noch besser abgefangen werden
  • print sollte umgeleitet werden, siehe self.guiPrint(), Frage: kann man std.out umleiten auf die Nachrichtenbox ?
  • Es sollten weitere Skripte mit Hilfe von Checkboxen und Radiobuttons integriert werden
  • Leider wurde noch nicht alles getestet, Mittester sind erwünscht ;)
  • Beim Speichern gibt es noch einen Fehler beim Dateinamen; auf ungültige Zeichen parsen
  • Beim Laden von lokalen Dateien gibt es manchmal Encodingfehler, Grund noch nicht klar

Dateiformat für den Multi-Uploader[Bearbeiten]

Es muss eine gewöhnliche Textdatei sein, die folgende Steuerkommandos enthält:

###mediawiki###Seitenname1###Kommentar1
Was auch immer, jeder Wikibefehl, wie in der Editbox beim Bearbeiten einer Seite.
###mediawiki###Seitenname2###Kommentar2
Was auch immer, jeder Wikibefehl, wie in der Editbox beim Bearbeiten einer Seite.
###mediawiki###MediawikiMultiuploadEnde

Oder als konkretes Beispiel:

###mediawiki###Zusatzinformationen für angehende Söldner im Kh^omkrieg###Mi zum Khomkrieg
=Zusatzinformationen für angehende Söldner im Kh^omkrieg=
Das fällt mir zu dem Thema ein:
*bla
*blub
[[Kategorie:Meistertipps]]
###mediawiki###Khomkriegsöldner###redir
[[#REDIRECT Zusatzinformationen für angehende Söldner im Kh^omkrieg]]
###mediawiki###MediawikiMultiuploadEnde
  • Die erste Zeile und jede weitere Trennzeile muss so aussehen: '###mediawiki###Seitenname###Kommentar'<br
Dabei ist
Seitenname z.B. 'Publikationen:Egal was auch immer'
Kommentar ist optional und wird dann statt des Standardkommentars ausgegeben
z.B. '###mediawiki###Sandkasten###kleine Änderungen von BenutzerX'
wird kein Kommentar angegeben, kommt der Standardkommentar
'Roboted: Neu erzeugt durch ' + config.username
  • Seperate Letzte Zeile: '###mediawiki###MediawikiMultiuploadEnde' """

Um Probleme rechtzeitig erkennen zu können, sollten allerdings nicht zuviele Seiten auf einmal hochgeladen werden.

Source des WAbotTK[Bearbeiten]

Achtung!
Im Quelltext nach XXX suchen und durch / ersetzen!

#!/usr/bin/python
# -*- coding: utf-8  -*-

u"""Dieses GUI steuert Skripte des PyWikipediaBot-Pakets
(http://sourceforge.net/projects/pywikipediabot) und 
wurde für das Wiki Aventurica (http://wiki.dsa4.de) programmiert.

Damit die Robotskripte hier funktionieren können, müssen zahlreiche
Dinge angepasst werden.
Siehe hierzu http://dsa4.de/wiki/index.php?title=Wiki_Aventurica:Robots

Getestet wurde das GUI mit der Version "pywikipediabot-snapshot20050323".
Ältere Pakete sind nicht kompatibel.
----
ACHTUNG: Da es Probleme mit dem Python-IDLE unter Windows gibt,
muss das Programm über die Kommandozeile, also mit
   "python WAbotTK.py" gestartet werden.
--->Ansonsten kommen "IOError"-Fehlermeldungen in rpc.py
(unter Python-2.3.5/Linux scheint es diese Probleme nicht zu geben)
----
Leider finden mehrere Ausgaben und Eingaben noch über die Konsole
statt, weil die meisten Skripte (noch) nicht GUI-freundlich umgeschrieben
worden sind. Vielleicht ändert sich das aber bald.
"""
__version__='$Id: WAbotTK.py,v 0.80 2005/05/24 19:30:00 Alrik Exp $'
__md5__=''

# Distributed under the terms of the PSF license.

global botPaketFehlt,tkinterFehlt,soundOK
import sys, os, time, httplib, re, thread, pickle #Module aus standard Python
try: import config, wikipedia #Module aus dem pywikipediabot-Paket
except ImportError: botPaketFehlt=True #Paket wurde nicht installiert, dann geht es natürlich nicht
else: botPaketFehlt=False
try:
    from Tkinter import *
    from ScrolledText import *
    from tkMessageBox import *
    from tkFileDialog import *
    from tkSimpleDialog import *
except ImportError: tkinterFehlt=True
else: tkinterFehlt=False

try: import winsound
except ImportError: soundOK = False #kein Win32 mit Sound
else: soundOK = True

class WAbotTK:
    """ Ein GUI, welches die PywikipediaBot-Skripte aufruft, die für das Wiki Aventurica
    angepasst wurden. Zur weiteren Dokumentation siehe die einzelnen __doc__
    bzw. die Seiten im Wiki, vor allem diese:
    http://dsa4.de/wiki/index.php?title=Wiki Aventurica:Robots/WAbotTK ein GUI für die Robotskripte """   
    def __init__(self, WAFenster=None):
        global botPaketFehlt,soundOK
        if WAFenster == None:
            #neues Fenster erstellen
            WAFenster = Tk()
        self.Hauptfenster = WAFenster 
        fbreite,fhoehe = 750,600    #das setzt natürlich mindestens 800x600 voraus
        WAFenster.geometry(str(fbreite)+"x"+str(fhoehe)+"+1+1")
        WAFenster.title(u"WAbotTK - Ein GUI für Robobotskripte zur Wiki Aventurica")
#Variablen setzen
        self.Dateiname=self.StatusMerken=self.robotLog =""
        self.teilfaktor = 0.25
        self.bOnline = self.bBenutzerAbbruch = False
        self.bDebug = True #False
        if not botPaketFehlt: self.sUsername = config.username
        self.WAbotDatenDic = {}

#Eine Nachrichtenbox mit Scrollbar erstellen: Hier werden alle Ausgaben angezeigt
        self.frHauptframe = Frame(WAFenster, relief=RIDGE, padx=2, pady=2)
        self.frOben = Frame(self.frHauptframe, relief=GROOVE)
        laNachrichten = Label(self.frOben, text= u"""Nachrichten und Ausgaben:""")
        laNachrichten.pack() #side=TOP, fill=BOTH, expand=1)
        self.Nachrichten= ScrolledText(self.frOben, height = 12, width = 90, background="#FFF7A7",
                                       fg = "black", font = ("Times New Roman",  10))
        self.Nachrichten.pack(side=TOP, fill=BOTH, expand=1) #anchor=N

#Eine Editbox mit Scrollbar erstellen: Hier werden die Texte dargestellt    
        self.frMitte = Frame(self.frHauptframe, relief=GROOVE)
        laEditbox = Label(self.frMitte, text= u"""Editierfeld zum Verändern von Daten (mit Such- und Markierfunktion):""")
        laEditbox.pack()
        self.EditBox= ScrolledText(self.frMitte, height = 18, width = 90, \
                                   background="#F7F7F7", fg = "black", font = ("Times New Roman", 11))
        self.EditBox.pack(side=TOP, fill=BOTH, expand=1) #anchor=N
        self.EditBoxInhalt = "" #ein Merker was wir dort gerade verarbeiten
        
       #anstatta pack wird place verwendet -> Resize-Funktion
        self.frOben.place(rely=0, relheight=self.teilfaktor, relwidth=1.0)
        self.frMitte.place(rely=self.teilfaktor, relheight=1.0-self.teilfaktor, relwidth=1.0)

        self.frZiehbalken = Frame(self.frHauptframe, bd=2, relief=RAISED, width=35, height=10, bg='#9a9a9a')
#Den Ziehbalken mit Pfeilen verzieren
##        self.laZiehbalkenbeschriftung = Label(self.frZiehbalken, text=u"^ v", bg='#9a9a9a')
##        self.laZiehbalkenbeschriftung.pack()
        self.frZiehbalken.place(relx=0.05, rely=self.teilfaktor) #, anchor=E)
        
        self.frHauptframe.pack(side=TOP, expand=YES, fill=BOTH)

        # Rahmen unten links, Textbox und Suchfeld
        self.frUntenLinks = Frame(WAFenster, bg='#FFFEAE', bd=2, relief=GROOVE)
        self.frUntenLinks.pack(side=LEFT, fill=BOTH, expand=1)        
        laSuche =Label(self.frUntenLinks,text=u"Suche:")
        laSuche.pack(side=LEFT)
        self.enSuchfeld = Entry(self.frUntenLinks,  bd="3")
        self.enSuchfeld.pack(side=LEFT)
        self.buFinden = Button(self.frUntenLinks,  padx=3, bd="3",text="finden und markieren", command=self.EditBoxFinden) #Thread)
        self.buFinden.pack(side=LEFT, padx=2)
        self.buErsetzen = Button(self.frUntenLinks,  padx=3, bd="3",text="Text ersetzen", command=self.EditBoxErsetzen) #Thread)
        self.buErsetzen.pack(side=LEFT, padx=4)
        self.buWikiTags = Button(self.frUntenLinks, text='Wikitags colorieren', bg='#c9c9a9', command=self.WikiTags) #Thread)
        self.buWikiTags.pack(side=LEFT, padx=1)
        self.buLinkFehler = Button(self.frUntenLinks, text=']| -> ] |', bg='#c9e9a9', command=self.LinkKorrektur) #Thread)
        self.buLinkFehler.pack(side=LEFT, padx=1)
        self.buVerarbeiten = Button(self.frUntenLinks, text='Hochladen', fg='blue', command=self.EditBoxVerarbeiten) #Thread)
        self.buVerarbeiten.pack(side=RIGHT)

        self.__MenuebefehleSetzen()
        self.Hauptfenster.config(menu=self.MenueLeiste) #anzeigen
        self.FensterPos()
        self.EditBoxLoeschen()
        self.__EventsSetzen()
        #gespeicherte Daten einlesen
        self.botKonfigLaden()

    def __MenuebefehleSetzen(self):
        u"Menübefehle"
        self.MenueLeiste = Menu(self.Hauptfenster)
        DateiMenue = Menu(self.MenueLeiste, tearoff=0)
        self.MenueLeiste.add_cascade(label="Datei", menu=DateiMenue)
        DateiMenue.add_command(label="Neu (Editbox löschen)", command=self.EditBoxLoeschen)
        DateiMenue.add_command(label="Datei einlesen ...", command=self.DateiEinlesen)
        DateiMenue.add_command(label="Speichern", command=self.Speichern)
        DateiMenue.add_command(label="Speichern als ...", command=self.SpeichernAls)
        DateiMenue.add_command(label="EditBox hochladen...", command=self.EditBoxVerarbeiten)
        DateiMenue.add_command(label="Drucken", command=self.Drucken, state=DISABLED)
        DateiMenue.add_separator()
        DateiMenue.add_command(label="user-config.py bearbeiten", command=self.UserConfigEinlesen)
        DateiMenue.add_separator()
        DateiMenue.add_command(label="Beenden -> X", command=self.Beenden, state=DISABLED)

        BearbeitenMenue = Menu(self.MenueLeiste, tearoff=0)
        self.MenueLeiste.add_cascade(label="Bearbeiten", menu=BearbeitenMenue)
        BearbeitenMenue.add_command(label=u"Rückgängig", command=self.EditUndo, state=DISABLED)
        BearbeitenMenue.add_command(label=u"Wiederherstellen", command=self.EditRedo, state=DISABLED)
        BearbeitenMenue.add_separator()
        BearbeitenMenue.add_command(label="Ausschneiden", command=self.EditAuss, state=DISABLED)
        BearbeitenMenue.add_command(label="Kopieren", command=self.EditKopi, state=DISABLED)
        BearbeitenMenue.add_command(label="Einfuegen", command=self.EditEinf, state=DISABLED)
        BearbeitenMenue.add_command(label="Alles markieren", command=self.EditMark)
        BearbeitenMenue.add_command(label="Suchen & ersetzen...", command=self.EditBoxErsetzen)
        BearbeitenMenue.add_separator()
        BearbeitenMenue.add_command(label=u"Belohnungen2Tabelle (=Text umformen)", command=self.Belohnungen2Tabelle)
        BearbeitenMenue.add_command(label=u"Mediawikifehler beheben= ']|' -> '] |'", command=self.LinkKorrektur)
        BearbeitenMenue.add_command(label=u"Eurosymbol korrigieren= '€' -> '€''", command=self.EuroSymbol2UTF)
        BearbeitenMenue.add_command(label=u"UTF-Umlaute korrigieren", command=self.UTFUmlaute2win)
        BearbeitenMenue.add_command(label=u"Text wikifizieren", command=self.Wikifizieren)

        SkripteMenue = Menu(self.MenueLeiste, tearoff=0)
        self.MenueLeiste.add_cascade(label="Login & Robotskripte", menu=SkripteMenue)
        SkripteMenue.add_command(label="Einloggen [F5]", command=self.LoginFunktion)
        SkripteMenue.add_command(label="Verbindungstest", command=self.VerbindungsTest) #Thread)
        SkripteMenue.add_command(label=u"Eintrag im Robotlog erstellen", command=self.RobotLogErweitern)
        SkripteMenue.add_separator()
        pySkripteMenue = Menu(SkripteMenue, tearoff=0)
        SkripteMenue.add_cascade(label="Robotskripte (nicht GUI-fähig)", menu=pySkripteMenue)
        SkripteMenue.add_separator()
        SkripteMenue.add_command(label="Multi-Uploadskript", command=self.SkriptUL)
        SkripteMenue.add_command(label="Text im Wiki ersetzen (Replace)", command=self.guiBotErsetzenSkript)
        SkripteMenue.add_separator()
        SkripteMenue.add_command(label="Seite zum Bearbeiten einlesen", command=self.SeiteEinlesen)
        SkripteMenue.add_command(label="Inhalt der Editbox hochladen", command=self.Hochladen)

        pySkripteMenue.add_command(label="Login (ohne GUI !)", command=self.botLoginKonsole)
        pySkripteMenue.add_command(label="Replace", command=self.botReplaceKonsole)
        pySkripteMenue.add_command(label="Redirect DOUBLE (doppelte korrigieren)", command=self.botRedirectDouble)
        pySkripteMenue.add_command(label="Redirect BROKEN (leere Redirs löschen, nur sysop!)", command=self.botRedirectBroken)
        pySkripteMenue.add_command(label="Check externe Links auf allen Seiten", command=self.botCheckExtern)
        pySkripteMenue.add_command(label="Touch all (Cache im Server erneuern)", command=self.botTouchAll)
        pySkripteMenue.add_separator()

        DebugMenue = Menu(self.MenueLeiste, tearoff=0)
        self.MenueLeiste.add_cascade(label=u"(Debug)", menu=DebugMenue)
        DebugMenue.add_command(label="Text im Nachrichtfenster anhaengen", command=self.Nachrichterzeugen)
        DebugMenue.add_command(label="Text im Editfenster anhaengen", command=self.Editanfuegen)
        DebugMenue.add_command(label="Variablen ausgeben + Toggle self.bDebug", command=self.VariablenAusgeben)
        DebugMenue.add_command(label="Statusbar -> online", command=Statuswert.online)
        DebugMenue.add_command(label="Statusbar -> offline", command=Statuswert.offline)
        
        AnzeigeMenue = Menu(self.MenueLeiste, tearoff=0)
        self.MenueLeiste.add_cascade(label=u"Optionen", menu=AnzeigeMenue)
        AnzeigeMenue.add_command(label="Fenster in rechte obere Ecke", command=self.FensterPos)
        AnzeigeMenue.add_command(label="Fenster in linkere obere Ecke", command=self.FensterPos, state=DISABLED)        
        AnzeigeMenue.add_command(label="Wikitags colorieren", command=self.WikiTags)        
        AnzeigeMenue.add_separator()
        AnzeigeMenue.add_command(label="Update des RobotGUI", command=self.Update, state=DISABLED)
        
        HilfeMenue = Menu(self.MenueLeiste, tearoff=0)
        self.MenueLeiste.add_cascade(label="Hilfe", menu=HilfeMenue)     
        HilfeMenue.add_command(label="Hilfe zum Wiki", command=self.Hilfe)
        HilfeMenue.add_command(label="Hilfe zum WAbotTK und den Robotskripten", command=self.Hilfe)        
        HilfeMenue.add_separator()
        HilfeMenue.add_command(label="Über / About", command=self.About)        
        
    def __EventsSetzen(self):
        u"""Events /Tooltips bei MouseOver-Event anzeigen
        Todo: eventuell + Mauscursor ändern:  z.B. head bzw.  double_arrow"""
        self.buVerarbeiten.bind("<Enter>", self.evVerarbeitenTooltip) 
        self.buVerarbeiten.bind("<Leave>", self.evStatusbarReset)
        self.buLinkFehler.bind("<Enter>", self.evLinkFehlerTooltip)
        self.buLinkFehler.bind("<Leave>", self.evStatusbarReset)
        self.buWikiTags.bind("<Enter>", self.evWikiTagsTooltip)
        self.buWikiTags.bind("<Leave>", self.evStatusbarReset)
        self.buErsetzen.bind("<Enter>", self.evErsetzenTooltip)
        self.buErsetzen.bind("<Leave>", self.evStatusbarReset)
        self.buFinden.bind("<Enter>", self.evFindenTooltip)
        self.buFinden.bind("<Leave>", self.evStatusbarReset)
        self.Hauptfenster.bind("<Control-o>", self.DateiEinlesen)
        self.Hauptfenster.bind("<Control-s>", self.EditBoxVerarbeiten)
        self.Hauptfenster.bind("<F1>", self.Hilfe)
        self.Hauptfenster.bind("<F5>", self.LoginFunktion)
        self.frZiehbalken.bind("<B1-Motion>", self.evVergroessern)  #wenn der Frame bewegt wird, Fenstergröße ändern
        self.frZiehbalken.bind("<Enter>", self.evBeschreibungsTooltip) #Tooltip bei MouseOver anzeigen
        self.frZiehbalken.bind("<Leave>", self.evStatusbarReset) #Tooltip bei MouseOver anzeigen
##        self.laZiehbalkenbeschriftung.bind("<B1-Motion>", self.evVergroessern)  #wenn der Label bewegt wird, Fenstergröße ändern
##        self.laZiehbalkenbeschriftung.bind("<Enter>", self.evBeschreibungsTooltip) #Tooltip bei MouseOver anzeigen
##        self.laZiehbalkenbeschriftung.bind("<Leave>", self.evStatusbarReset) #Tooltip bei MouseOver anzeigen
        
#Events verarbeiten
    def evVergroessern(self, event):
        u"Framegröße anpassen und verschieben"
        offset_y = 40.0 #Mindestabstand, sonst unwiederbringliches Verschieben
        frame_y = event.widget.master.winfo_rooty()
        frame_height = float(event.widget.master.winfo_height())
        maus_y = event.y_root
        delta_y = float(int(maus_y) - int(frame_y))
        if delta_y<offset_y:            #nur in diesem Bereich
            delta_y = offset_y
        elif delta_y>frame_height - offset_y:
            delta_y = float(int(frame_height) - int(offset_y))       
        split = delta_y / frame_height #Verhältnis
        self.frOben.place(relheight=split)
        self.frMitte.place(rely=split, relheight=1.0-split)
        self.frZiehbalken.place(relx=0.05, rely=split) #, anchor=E)
#Tooltips
    def evBeschreibungsTooltip(self,event):
        u"Tooltip bei Mouse-Over-Event =<Enter> über Verschiebebalken anzeigen"
        self.StatusMerken = Statuswert.lesen()
        Statuswert.setzen(u"Mit diesem Kästchen kann die vertikale 'Höhe' der Boxen eingestellt werden.")
    def evVerarbeitenTooltip(self,event):
        u"Tooltip bei Mouse-Over-Event =<Enter> über 'Verarbeiten'-Button anzeigen"
        self.StatusMerken = Statuswert.lesen()
        Statuswert.setzen(u"Es folgt eine Abfrage und der Text kann gespeichert und/oder upgeloaded werden.")
    def evLinkFehlerTooltip(self, event):
        u"Tooltip bei Mouse-Over-Event =<Enter> über 'LinkFehler'-Button anzeigen"
        self.StatusMerken = Statuswert.lesen()
        Statuswert.setzen(u"Mit dieser Funktion kann der Mediawikifehler zu Links in Tabellen ausgebügelt werden.")
    def evFindenTooltip(self, event):
        u"Tooltip bei Mouse-Over-Event =<Enter> über 'Finden'-Button anzeigen"
        self.StatusMerken = Statuswert.lesen()
        Statuswert.setzen(u"Textausschnitt in der Editbox finden und rot eingefärbt anzeigen.")
    def evErsetzenTooltip(self, event):
        u"Tooltip bei Mouse-Over-Event =<Enter> über 'Text ersetzen'-Button anzeigen"
        self.StatusMerken = Statuswert.lesen()
        Statuswert.setzen(u"Textausschnitt in der Editbox suchen und ersetzen. Momentan nicht interaktiv, d.h. ALLE Treffer werden sofort ersetzt.")
    def evWikiTagsTooltip(self, event):
        u"Tooltip bei Mouse-Over-Event =<Enter> über 'WikiTags'-Button anzeigen"
        self.StatusMerken = Statuswert.lesen()
        Statuswert.setzen(u"Alle WikiTags einfärben (Syntax-Highlightning).")
    def evStatusbarReset(self,event):
        u"Statusbar wieder zurücksetzen, z.B. wg. Tooltip"
        if self.StatusMerken!="":
            Statuswert.setzen(self.StatusMerken)
            self.StatusMerken=""
        else: Statuswert.loeschen()

    def Beenden(self):
        u"Throttle abstellen und Programm beenden"
        wikipedia.stopme()
        self.botKonfigSpeichern()
        self.Hauptfenster.quit()  
    def About(self):
        u"About-Fenster anzeigen"
        global docstring         #den docstring des ganzen Moduls nehmen = Tipparbeit sparen
        showinfo("About: WAbotTK", __version__+"\n"+docstring)
    def Hilfe(self,*parameter):
        u"Hilfe-Fenster anzeigen"
        showinfo("Wo bekommt man Hilfe?", u"""Hilfe ist auf der Seite: http://dsa4.de/wiki/index.php?title=Wiki_Aventurica:Hilfe zu bekommen.
        Direkt zum Robot und zum WAbotTK gibt es hier Hilfe: http://dsa4.de/wiki/index.php?title=Wiki_Aventurica:Robots
        Die einzelnen Robotskripte sind bisher kaum dokumentiert und erfordern also eine Einarbeitung in den Quelltext.
        Siehe auch:  http://sourceforge.net/projects/pywikipediabot/""")

    def Baustelle(self):
        u"Hierhin jede Funktion verbiegen, die noch nichts macht"
        global soundOK
        funktioniertnicht = "Drucken, Uploaden,Bearbeiten/Ausschneiden/Kopieren/Einfügen, Mediawikifehler beheben"
        if soundOK: winsound.PlaySound('SystemAsterisk', winsound.SND_ALIAS)
        else: bell()
        self.guiPrint(u"Diese Funktion ist noch nicht eingebaut. ;-) Verbesserungsvorschlaege bitte mitteilen. - Im Moment funktioniert nicht:\n   %s" % funktioniertnicht)

    def botKonfigLaden(self):
        u"""Variablen und Benutereinstellungen einlesen"""
        try:
            f = file("WAbotTk.dat", "r")
            self.WAbotDatenDic = pickle.load(f)
            f.close()
        except:
            print u"Das Lesen der Bot-Konfig hat nicht geklappt."
            if self.bDebug: self.guiPrint(u"%s - Das Lesen der Bot-Konfig hat nicht geklappt." % self.logZeit())
            self.WAbotDatenDic = {}            

    def botKonfigSpeichern(self):
        u"""Variablen und Benutzereinstellungen in einer Datei speichern, die
        beim Start des GUI wieder eingelesen werden können."""
        try:
            f = file("WAbotTk.dat", "w")
            pickle.dump(self.WAbotDatenDic,f)
            f.close()
        except:
            if self.bDebug: self.guiPrint(u"%s - Das Schreiben der Bot-Konfig hat nicht geklappt." % self.logZeit())

    def UserConfigEinlesen(self):
        u"Die Datei user-config.py zum Bearbeiten einlesen"
        pfad = os.path.dirname(os.path.abspath(sys.argv[0])) #auf win32 abspath notwendig
        userconfig = os.path.normpath(pfad+"/user-config.py") #plattformunabhängig
        self.DateiEinlesen(userconfig)
        
    def DateiEinlesen(self, *parameter):
        u"Eine (angegebene) Datei öffnen und in die Editbox einlesen"
        try:
            dateiname=parameter[0]
        except IndexError:
            dateiname=""
        if dateiname=="":
            dateiname= askopenfilename(parent=self, title=u"Datei Öffnen...", defaultextension='*.*', filetypes=[('Alle Dateien','*.*'),
                                      ('Textdateien','*.txt'),('Wikidateien','*.wiki.txt')],initialfile=dateiname)
        try: fhDatei = open(dateiname,"r")
        except IOError:
            self.guiPrint(u"\n%s - Fehler! beim Öffnen von %s" % (self.logZeit(),dateiname) )
            if self.bDebug: self.guiPrint(u"WA-DEBUG %s : sys.argv[0]= '%s'" % (self.logZeit(),sys.argv[0]) )
            self.Dateiname=""
            Statuswert.setzen(u"Fehler! '%s' konnte nicht geöffnet und eingelesen werden." % dateiname)
        else:
            try:
                inhalt = fhDatei.read()
            except IOError:
                self.guiPrint(u"\n%s - Fehler! beim Auslesen von %s" % (self.logZeit(), dateiname) )
                self.Dateiname=""
                Statuswert.setzen(u"Fehler! '%s' konnte nicht eingelesen werden." % dateiname)                
            else:
                fhDatei.close()
                self.EditBoxInhalt="Datei:"+dateiname
                self.Dateiname=dateiname
                Statuswert.setzen(u"'%s' wurde eingelesen - bitte bearbeiten und mit 'Verarbeiten' speichern." % dateiname)

                inhalt=self.umwandeln(inhalt, "utf-8") #Um Encodingproblemen aus dem Weg zu gehen, nach UTF-8 umwandeln
                self.EditBoxLoeschen()
                self.edit(inhalt)

    def umwandeln(self, text, parameter):
        u"""Den String mit mehreren Verfahren in Unicodezeichen umwandeln versuchen
           bzw. wieder in eine andere Kodierung zurückwandeln z.B: CP1252"""
        if parameter=="utf-8": #decodieren
            try: ergebnis=text.decode('utf-8')
            except UnicodeDecodeError:
                self.guiPrint(u"UnicodeDecodeError, wir versuchen CP1252")
                try: ergebnis = text.decode("CP1252")
                except UnicodeDecodeError:
                    self.guiPrint(u"UnicodeDecodeError auch bei CP1252, wir versuchen cp850")
                    try: ergebnis = text.decode("cp850")
                    except UnicodeDecodeError:
                        self.guiPrint(u"UnicodeDecodeError auch bei CP850, wir versuchen cp437")
                        try: ergebnis = text.decode("cp437")
                        except UnicodeDecodeError:
                            self.guiPrint(u"UnicodeDecodeError - auch bei cp437 wir versuchen latin-1")
                            try: ergebnis = text.decode("latin-1")
                            except UnicodeDecodeError:
                                self.guiPrint(u"UnicodeDecodeError auch bei latin-1, wir versuchen noch iso-8859-1")
                                try: ergebnis = text.decode("iso-8859-1")
                                except:
                                    self.guiPrint(u"UnicodeDecodeError - mit Bosparano am Ende... Wer hat ne Idee?")
                                    showerror("Achtung UnicodeDECODE-Error!", u"Es ist ein UnicodeDecodeError aufgetreten, beim Versuch das Format '%s' umzuwandeln.\nKeine der folgenden Encodings hat funktioniert:cp850,cp437,cp1252,iso-8859-1,latin-1,utf-8\nEs wird also ein Leerstring zurückgegeben." % parameter)
                                    raise Uploadfehler
                                else: return ergebnis
                            else: return ergebnis
                        else: return ergebnis
                    else: return ergebnis
                else:return ergebnis
            else: return ergebnis
        else: #encodieren
            try: ergebnis=text.decode('utf-8').encode(parameter)
            except UnicodeEncodeError:
                self.guiPrint(u"UnicodeEncodeError beim Format '%s', es wurde ein leerer String zurückgegeben" %parameter)
                showerror("Achtung UnicodeENCODE-Error!", u"Es ist ein UnicodeEncodeError aufgetreten, beim Versuch das Format '%s' umzuwandeln.\nEs wird also ein Leerstring zurückgegeben." % parameter)
                return ""
            else: return ergebnis
            
    def Speichern(self):
        "Inhalt der Editbox ohne Nachfrage abspeichern, sofern der Dateiname bekannt ist"
        if not self.Dateiname:
            self.SpeichernAls()
        else:
            #if self.bDebug: self.guiPrint(u"Speichern: ...")
            alt=self.Dateiname                   
            self.Dateiname = self.ErlaubteDateizeichen(self.Dateiname)
            if alt!=self.Dateiname:
                self.guiPrint(u"Speichern: Der Dateiname '%s' ist nicht erlaubt und wurde in '%s' geändert." % (alt, self.Dateiname))
            try: fHandle=open(self.Dateiname,'w')
            except IOError:
                self.guiPrint(u"%s - Fehler beim Versuch die Datei '%s' zum Speichern zu öffnen!" % (self.logZeit(), self.Dateiname))
                self.Dateiname=""
                Statuswert.setzen(u"Fehler! '%s' konnte nicht zum Speichern geöffnet werden." % self.Dateiname)
            else:
                try:
                    zwischen=self.EditBox.get(1.0,END)
                    fHandle.write(zwischen)
                except UnicodeEncodeError:
                    zwischenUTF=self.umwandeln(zwischen, "cp1252") #todo: Encoding je nach OS ermitteln
                    try: fHandle.write(zwischenUTF)
                    except:
                        self.guiPrint(u"Fehler beim Versuch die Datei '%s' zum Speichern zu öffnen!" % self.Dateiname)
                        self.Dateiname=""
                        Statuswert.setzen(u"Fehler! '%s' konnte nicht zum Speichern geöffnet werden." % self.Dateiname)
                    else:    
                        fHandle.flush()
                        fHandle.close()
                        Statuswert.setzen(u"'%s' wurde gespeichert." % self.Dateiname)

    def SpeichernAls(self):
        if self.bDebug: self.guiPrint(u"##Speichern als... wurde ausgelöst.")
        if self.Dateiname=="" and self.EditBoxInhalt.startswith("Wikiseite:"):
            self.Dateiname = self.EditBoxInhalt[len("Wikiseite:"):]
            self.Dateiname = self.ErlaubteDateizeichen(self.Dateiname)
        tempDateiname=asksaveasfile(filetypes=[('Alle Dateien','*.*'),('Textdateien','*.txt'), ('Wikidateien','*.wiki.txt')],
                                    initialfile=self.Dateiname, defaultextension='*.txt')
        if tempDateiname:
            self.Dateiname=tempDateiname.name
            if self.bDebug: self.VariablenAusgeben(u"##Speichern als ... mitte")        
            self.Speichern()
        else:
            showinfo(u"Achtung!Nicht gespeichert.", u"Es wurde kein Dateiname ausgewählt, daher auch nicht gespeichert.")
            self.Dateiname=""
            Statuswert.setzen(u"Fehler! '%s' konnte nicht gespeichert werden, weil kein Dateiname gewählt wurde." % self.Dateiname)

    def ErlaubteDateizeichen(self,dateinamemitpfad):
        ergebnis=dateinamemitpfad
        nichterlaubt=u"\?\*<>\|" #ur"<>" ##u":?*<>|"  #der Rest ?* funktioniert noch nicht-> Fehler in re
        #pfad = os.path.dirname(os.path.abspath(dateinamemitpfad)) #auf win32 abspath notwendig
        #dateiname =dateinamemitpfad.split(pfad)
        for z in nichterlaubt:
            ergebnis = re.sub(z, "_", ergebnis)
        return ergebnis
        
    def Drucken(self):
        self.Baustelle()
    def Update(self):
        self.Baustelle()
#Funktionen zur oberen Nachrichtenbox
    def guiPrint(self, text):
        """Bisher verwenden fast alle Skripte die Funktion "print" die nicht gerade GUI-freundlich ist.
       Wo immer es möglich ist, diese Funktion statt "print" verwenden.
       Todo: Im Prinzip kann sys.stdout und sys.stderr hierher umgeleitet werden. Fehlt noch sys.stdin."""
##        print text                       #eventuell den Text zusätzlich in der Shell ausgeben
        self.Nachricht(text+"\n")
    def Nachricht(self, nachr):
        """Text am Ende des Nachrichtenfensters anfügen und automatisch scrollen"""
        #self.nachr = None
        self.Nachrichten.insert(END, nachr)
        self.Nachrichten.tag_add('all', '1.0', END)
        self.Nachrichten.tag_config('all', wrap=WORD)        
        self.Nachrichten.see(END)

#Testfunktionen        
    def Nachrichterzeugen(self):
        "Eine einzelne Zeile in die Nachrichtenbox schreiben (Scroll-test)"
        self.guiPrint(u"\nTest von Scrollbar und autoscroll\nText wurde angefügt\n")        
    def Editanfuegen(self):
        "Eine einzelne Zeile in die Editbox schreiben (Scroll-test)"
        self.edit(u"\nTest von Scrollbar und autoscroll\nText wurde angefügt\n")
    def VariablenAusgeben(self, *parameter):
        u"Zum Debuggen Variablen ausgeben, zusätzlich self.bDebug toggeln"
        try:  sAusgabe=parameter[0]
        except IndexError:
            sAusgabe=""
        self.guiPrint(u"\n%s self.Dateiname='%s', self.bOnline='%s', self.robotLog='%s',\n die lezten 5 Zeichen der Editbox lauten:'%s'" % (sAusgabe, self.Dateiname,self.bOnline, self.robotLog, self.EditBox.get(1.0,END)[-5:]) )        
        if self.bDebug:
            self.bDebug=False
            self.guiPrint(u"Toggle: self.bDebug ist jetzt ausgeschaltet\n---")
        else:
            self.bDebug=True
            self.guiPrint(u"Toggle: self.bDebug ist jetzt eingeschaltet\n---")

    def FensterPos(self,*parameter):
        if len(parameter)==0:  
            breite,hoehe = 750,640
            x,y = self.Hauptfenster.winfo_screenwidth()-breite-1, 1  #recht obere Ecke
        elif len(parameter)!=4:  breite,hoehe,x,y = 750,640,1,1 #linke obere Ecke
        else: breite,hoehe,x,y=parameter[0],parameter[1],parameter[2],parameter[3]
        self.Hauptfenster.geometry(str(breite)+"x"+str(hoehe)+"+"+str(x)+"+"+str(y))
 
#Befehle rund um die Editbox
    def EditBoxVerarbeitenThread(self):
        thread.start_new_thread(self.EditBoxVerarbeiten,())
    def EditBoxVerarbeiten(self):
        u"Die Daten aus der Editbox abspeichern und/oder veröffentlichen"
##        if self.EditBoxInhalt.startswith("Datei:"):
##            self.SpeichernAls()
##        elif self.EditBoxInhalt.startswith("Wikiseite:"):
##            self.Hochladen()
##        else:
##            auswahl = askyesno(u" )
##            if auswahl:
##            
##            self.guiPrint(u"\nEigentlich sollte dieser Fall nicht eintreten. EditboxInhalt='%s'. Es wird einfach mal die Upload-Routine gesartet" % self.EditBoxInhalt)
##            self.Hochladen()
        auswahl = askyesno("Hochladen...", u"Soll der Artikel hochgeladen werden?" )
        if auswahl and len(self.EditBoxInhalt)>1:  self.Hochladen()
        else: self.guiPrint(u"Benutzerabbruch: Upload nicht gestartet oder EditBox leer")
    def EditUndo(self):
        self.EditBox.edit_undo()  #funktioniert leider nicht, wieso ?
    def EditRedo(self):
        self.EditBox.edit_redo()  #funktioniert leider nicht, wieso ?
    def EditAuss(self):
        self.Baustelle()
    def EditKopi(self):
        self.Baustelle()
    def EditEinf(self):
        self.Baustelle()
    def EditMark(self):
        #self.Nachrichten.tag_add('all', '1.0', END)
        self.Nachrichten.tag_add("sel", "1.0", END)
        self.Nachrichten.mark_set("insert", "1.0")
        self.Nachrichten.see("insert")
        return "break"

    def EditBoxLoeschen(self):
        u"Die Editbox mit Nachfrage löschen"
        inhalt = self.EditBox.get("1.0",END)
        if inhalt != "" and len(inhalt)>1:
            auswahl = askyesno(u"Textbox löschen?", u"In der Textbox befindet sich noch Text (=%d Zeichen). Soll dieser Text (unwiederbringlich!) gelöscht werden?" % len(inhalt) )
            if auswahl:
                self.EditBox.delete("1.0", END)
                return True
            else:
                self.guiPrint(u"Benutzerabbruch: Weil der Text nicht gelöscht werden durfte, wurd der Vorgang abgebrochen.")
                return False
    def edit(self, text):
        u"""Text am Ende der Editbox anfügen (eventuell vorher löschen=neuer Text)"""
        #self.text = None
        self.EditBox.insert(END, text)
        self.EditBox.tag_add('all', '1.0', END)
        self.EditBox.tag_config('all')
    def EditBoxErsetzenThread(self):
        thread.start_new_thread(self.EditBoxErsetzen,())
    def EditBoxErsetzen(self, *parameter):
        u"""Text in der Editbox suchen und ersetzen, die Anzahl der Ersetzungen zählen und ausgeben
        Todo: Interaktive Abfrage
        --im prinzip wäre string.replace(alt,neu) schneller, dann aber nur schlecht interaktiv machbar"""
        if len(parameter)==2: #ohne Beschreibungstext
            suchen, ersetzen, beschreibungstext = str(parameter[0]), str(parameter[1]), u""
        elif len(parameter)==3: #mit
            suchen, ersetzen, beschreibungstext = str(parameter[0]), str(parameter[1]), str(parameter[2])
        else:
           #todo: Abfragefenster mit 2 Zeilen untereinander
            suchen=askstring("Suchen nach", u"Nach was soll gesucht werden?")
            ersetzen=askstring("Ersetzen durch", u"Mit was soll '%s' ersetzt werden ? (Achtung: Es werden alle Vorkommnisse ohne Nachfrage ersetzt!)" % suchen)
            beschreibungstext=u"Textersetzung '%s' -> '%s' " % (suchen, ersetzen)

        inhaltEditbox=self.EditBox.get(1.0,END)
        if suchen in inhaltEditbox:
            aufgeteilt=inhaltEditbox.split(suchen)
            ergebnis=""
            for teil in aufgeteilt:
                ergebnis += teil
                ergebnis += ersetzen
            if ergebnis[:-1].endswith(ersetzen): ergebnis=ergebnis[:-len(ersetzen)-1] #einmal zuviel + zusätzliches EOF-Zeichen
            if self.bDebug: self.guiPrint(u"-ergebnis endet mit '%s'" % ergebnis[-5:])
            self.EditBox.delete("1.0", END)  ##ohne Abfrage löschen
            #self.EditBoxLoeschen() ##so ist es sicherer aber nerviger
            self.EditBox.insert(END,ergebnis)
            self.WikiTags()
            self.guiPrint(u"%s - %s mit (%d Ersetzungen)." % (self.logZeit(), beschreibungstext, len(aufgeteilt)-1) )
        else:
            self.guiPrint(u"%s - %s:Keine '%s' enthalten." % (self.logZeit(), beschreibungstext, suchen) )

#Spezielle Aufrufe der Ersetzfunktion
    def LinkKorrekturThread(self):
        thread.start_new_thread(self.LinkKorrektur,())
    def LinkKorrektur(self):
        u"""Den Text nach ]| durchsuchen und ] | daraus machen, um den
        Mediawikifehler (Version 1.4.0) zu beheben."""
        suchen   = u"]|"
        ersetzen = u"] |"
        self.EditBoxErsetzen(suchen,ersetzen, u"Mediawikifehler wurden korrigiert: ")

    def UTFUmlaute2winThread(self):
        thread.start_new_thread(self.UTFUmlaute2win,())
    def UTFUmlaute2win(self):
        u"""Dummerweise werden die Daten beim Abspeichern (noch) nicht umkodiert.
        Daher muss man sich vorerst anders behelfen und eben einfach den ganzen Mist ersetzen lassen."""
        tauschDic ={"auml" : [u"Ã"+"¤", u"ä"], "Auml" : [u"Ã"+"„", u"Ä"],
                    "ouml" : [u"Ã"+"¶", u"ö"], "Ouml" : [u"Ã"+"–", u"Ö"],
                    "uuml" : [u"Ã"+"¼", u"ü"], "Uuml" : [u"Ã"+"Å“", u"Ü"], "szlig" : [u"Ã"+"Ÿ", u"ß"]}
        for element in tauschDic:
            suchen  =tauschDic[element][0]
            ersetzen=tauschDic[element][1]
            self.EditBoxErsetzen(suchen,ersetzen, u"UTF-Umlaut '%s' wurde korrigiert: " % str(element))
    def EuroSymbol2UTF(self):
        u"""beim Eurosymbol '€' hilft die Funktion "umwandeln()" nicht bzw. der Robot kann nicht uploaden
        vermutlich liegt das am fehlenden Encoding im pywikipediabot-paket. Abhilfe: HTML4.0-code €"""
        suchen=u"€"
        ersetzen=u"€"
        self.EditBoxErsetzen(suchen,ersetzen, u"Eurosymbol € wurde in HTML4.0-code € umgewandelt:")
#Suchen und farbliches Hervorheben aller Vorkommnisse
    def EditBoxFindenThread(self):
        thread.start_new_thread(self.EditBoxFinden,())
    def EditBoxFinden(self):
        u"""Action-function for the Button: highlight all occurrences of string.
        Taken from O'Reilly's Python in a Nutshell."""
        #remove previous uses of tag 'found', if any
        self.EditBox.tag_remove('gefunden', '1.0', END)
        # get string to look for (if empty, no searching)
        s = self.enSuchfeld.get()
        if s:
            # start from the beginning (and when we come to the end, stop)
            idx = '1.0'
            while True:
                # find next occurrence, exit loop if no more
                idx =self.EditBox.search(s, idx, nocase=1, stopindex=END)
                if not idx:
                    break
                # index right after the end of the occurrence
                lastidx = '%s+%dc' % (idx, len(s))
                # tag the whole occurrence (start included, stop excluded)
                self.EditBox.tag_add('gefunden', idx, lastidx)
                # prepare to search for next occurrence
                idx = lastidx
            # use a red foreground for all the tagged occurrences
            self.EditBox.tag_config('gefunden', foreground='red')

    def WikiTagsThread(self):
        thread.start_new_thread(self.WikiTags,())
    def WikiTags(self):
        u"""Wiki-Tags farblich hervorheben, die Farben und Tags können sehr einfach erweitert werden.
        Für die Farbwahl z.B. 'pynche.pyw' benutzen und Werte dann hier eintragen.
        Es funktionieren aber auch '#ffffff'-Farbwerte.
        ToDo: Eigenes Konfigurationsmenü zur Farb/Tag-Wahl mit Abspeicherungsmöglichkeit.
        ToDo: RegExps verwenden, die die Syntax noch besser erfassen."""
        tagsucheDic= {"pink": [],
                              "purple": ["[","]","|","{{","}}"],
                              "brown" : ["'''","''","==","===","====","====="],
                              "blue" : ["<div","</div>", "<br/>","<center>","</center>", "<font", "</font>",
                                        "<nowiki>","<"+"/nowiki>","<pre>","<XXXpre>","<!--","-->"],
                              "orange" : ["{|","|}","{{{","}}}"],
#Die Abfrage von Returncodes geht leider nicht, z.B. weder mit '\n*', noch mit """<return>XY""" also mehrzeilig, was tun?:
#daher ist momentan "\n*", "\n#", "\n:*", "\n:","\n----" nicht korrekt abfragbar
                              "green" : ["""*""", """#""", """:*""", """----"""],
                              "#ff99ff" : ["{{PAGENAME}}","{{PAGENAMEE}}", "{{NUMBEROFARTICLES}}",
                                           "{{SERVER}}", "{{localurl:", "###mediawiki###"]}
        for farbe in tagsucheDic:
            farbindex = 'wikitag-'+farbe
            self.EditBox.tag_remove(farbindex, '1.0', END)
            for suchtag in tagsucheDic[farbe]:
                s=suchtag
                if s:
                    idx = '1.0'
                    while True:
                        idx =self.EditBox.search(s, idx, nocase=1, stopindex=END)
                        if not idx:
                            break
                        lastidx = '%s+%dc' % (idx, len(s))
                        self.EditBox.tag_add(farbindex, idx, lastidx)
                        idx = lastidx
            #Alle Tags farblich hervorheben
            self.EditBox.tag_config(farbindex, foreground=farbe)

    def Belohnungen2Tabelle(self):
        u"Aus den Daten von [[Belohnungen für Abenteuer]] eine Wiki-Tabelle machen"
        inhaltEditbox=self.EditBox.get(1.0,END)

        try: import bel2tab    #modul als externe Datei laden, Fehler abfangen
        except ImportError:
            pfad = os.path.dirname(os.path.abspath(sys.argv[0]))
            fehlertext=u"'bel2tab.py' konnte nicht importiert werden. Bitte von [[Wiki Aventurica:Werkzeuge]] herauskopieren und im Verzeichnis: '%s' speichern." % pfad 
            self.guiPrint("%s - %s" % (self.logZeit(),fehlertext))
            showerror(u"Skript fehlt", fehlertext)
        else:
#todo:Testen ob schon in Editbox, sonst vom Server holen
            b2t = bel2tab.Belohnung2Wikitabelle()            
            tabellentext = b2t.text2tab(inhaltEditbox,2)
            if self.EditBoxInhalt.startswith("Wikiseite:"): self.EditBoxInhalt+=u" (Tabelle)"
            else: self.EditBoxInhalt+=u"? (Tabelle)"
            #self.EditBox.delete("1.0", END)  ##ohne Abfrage löschen
            self.EditBoxLoeschen() ##so ist es sicherer
            self.EditBox.insert(END,tabellentext)  #Ergebnis wieder in die EditBox reinschreiben
            self.guiPrint(u"%s - Die Daten wurden verarbeitet und können nun abgespeichert oder hochgeladen werden -> Verarbeiten-Knopf." % self.logZeit())

    def Wikifizieren(self):
        u"Jeden Begriff in der Editbox wikifizieren, interaktiv oder alles auf einmal"
        inhaltEditbox=self.EditBox.get(1.0,END)
        try: import wikifizieren    #modul als externe Datei laden, Fehler abfangen
        except ImportError:
            pfad = os.path.dirname(os.path.abspath(sys.argv[0]))
            fehlertext=u"'wikifizieren.py konnte nicht importiert werden. Bitte von [[Wiki Aventurica:Werkzeuge]] herauskopieren und im Verzeichnis: '%s' speichern." % pfad 
            self.guiPrint("%s - %s" % (self.logZeit(),fehlertext))
            showerror(u"Skript fehlt", fehlertext)
        else:
#todo:Interaktive Abfrage, im Moment noch alles oder nichts
            wikify = wikifizieren.Wikify()            
            ergebnis = wikify.wikifizieren(inhaltEditbox)
            auswahl = askyesno("Wikifizierung...", u"Leider ist die Wikifizierung im Moment noch nicht interaktiv. Soll der Inhalt der Editbox komplett wikifiziert werden?")
            if auswahl: 
                self.EditBox.delete("1.0", END)  ##ohne Abfrage löschen
                #self.EditBoxLoeschen() ##so ist es sicherer
                self.EditBox.insert(END,ergebnis)  #Ergebnis wieder in die EditBox reinschreiben
                self.guiPrint(u"%s - Die Daten wurden verarbeitet und können nun abgespeichert oder hochgeladen werden -> Verarbeiten-Knopf." % self.logZeit())

    def logZeit(self):
        z=time.localtime()
        #Datum und Zeit im Format 'JJJJ-MM-TT ca. hh:mm'
        zeit=str(z[0])+"-"+str(z[1]).zfill(2)+"-"+str(z[2]).zfill(2)+" ca. "+str(z[3]).zfill(2)+":"+str(z[4]).zfill(2)
        return zeit
    def RobotLogErweitern(self):
        seite=u"Wiki_Aventurica:Roboteinsatz_Logfile"
        kommentar=u"im Logfile eingetragen"
        self.robotLog=askstring('Robot-Logfile ', 'Was soll im RobotLogfile nach dem Datum eingetragen werden?',
                                        initialvalue=self.robotLog)
        if self.robotLog!="":
            self.SeiteEinlesen(seite) #ab in die Editbox
            inhaltEditbox=self.EditBox.get(1.0,END)
            ergebnis=""
            if "<!-- diese Marke1" in inhaltEditbox:
                suchtext = u"<!-- diese Marke1 dient dem Robot zum automatischen Eintragen, bitte nicht entfernen -->"
                aufgeteilt=inhaltEditbox.split(suchtext)
                if len(aufgeteilt)==2:
                    ergebnis=aufgeteilt[0]+suchtext+"\012"+"*"+self.logZeit()+":"+self.sUsername+" - "+self.robotLog+aufgeteilt[1]
                else:
                    self.guiPrint(u"%s - RobotLog:Fehler bei Marke 1!" % self.logZeit())
            else:
                self.guiPrint(u"%s - RobotLog:Keine Marke1!" %self.logZeit())
            if "<!-- diese Marke2" in inhaltEditbox:
                suchtext = u"<!-- diese Marke2 dient dem Robot zum automatischen Eintragen, bitte nicht entfernen -->"
                aufgeteilt=ergebnis.split(suchtext)
                if len(aufgeteilt)==2:
                    ergebnis=aufgeteilt[0]+suchtext+"\012"+"*"+self.logZeit()+" "+self.sUsername+" - "+self.robotLog+aufgeteilt[1]
                else:
                    self.guiPrint(u"%s - RobotLog:Fehler bei Marke2!" % self.logZeit())
            else: self.guiPrint(u"%s - RobotLog:Keine Marke2!" % self.logZeit())
            inhaltEditbox=ergebnis
            self.EditBox.delete("1.0", END)  ##ohne Abfrage löschen
            #self.EditBoxLoeschen() ##so ist es sicherer aber nerviger
            self.EditBox.insert(END,inhaltEditbox)
            self.WikiTags()
            self.guiPrint(u"Bitte den Button 'Verarbeiten' klicken, um diese Daten hochzuladen.")
            #self.Hochladen(seite,inhaltEditbox,kommentar) #eventuell ohne Abfrage gleich hochladen
        else:
            self.guiPrint(u"%s - Weil self.robotLog leer ist, wird das Robotlogfile nicht erweitert." % self.logZeit())
                                        
##################################################################################
#ab hier die eigentlichen Robot-Skripte
##################################################################################

#eine Seite im RAW-Format lesen und in EditBox zum Bearbeiten bereitstellen
    def SeiteEinlesen(self,*parameter):
        u""""Eine Seite einlesen und in die EditBox einfügen."""
        mysite = wikipedia.getSite()
        if not self.bOnline:
            self.guiPrint(u"ACHTUNG! Nicht eingeloggt!")
            showerror("Achtung !", u"Um die einzelnen netzgestützten Funktionen des RobotGUI benutzen zu können, muss man eingeloggt sein. Das ist momentan nicht der Fall. Wenn Cookies bereits gespeichert wurden, reicht auch der 'Verbindungstest'.")
        else:
            if len(parameter)==0:
                Seitentitel = askstring('Seitenname', 'Bitte den Namen der Seite angeben, die eingelesen werden soll (Spezial:... geht leider noch nicht):',
                                        initialvalue=u"Belohnungen für Abenteuer")
            else: Seitentitel=parameter[0]
            for i in range(1,3):    ##2 Versuche
                if Seitentitel=="": Seitentitel=" " #sonst Attributerror
                try:
                    pl = wikipedia.PageLink(mysite, Seitentitel)
                except AttributeError:
                    self.guiPrint(u"%s - SeiteEinlesen: AttributeError bei Seite '%s' aufgetreten." % (self.logZeit(), Seitentitel))
                else:
                    if pl.exists():
                        self.EditBoxInhalt="Wikiseite:'"+Seitentitel+"'"
                        try:
                            Seiteninhalt = pl.get()
                        except wikipedia.IsRedirectPage, RedirectSeitentitel:
                            self.guiPrint(u"Die Seite ist eine Redirectseite! Es wird nun direkt diese Seite: '%s' angesprungen und eingelesen." % RedirectSeitentitel)
                            Seitentitel = RedirectSeitentitel
                            wikipedia.stopme() #sonst Fehler mit IsRedirectPage
                        else:
                            break
                    else:
                        self.guiPrint(u"\nDie Seite '%s' gibt es nicht." % Seitentitel)
                        self.EditBoxInhalt=""
                        break
            if Seiteninhalt=="":
                self.guiPrint(u"%s - Das hat wohl nicht geklappt... Die Seite '%s' konnte nicht geöffnet werden." % (self.logZeit(), Seitentitel))
            else:
                self.EditBox.delete("1.0", END)
                self.edit(Seiteninhalt)
                self.WikiTags() #gleich einfärben
            wikipedia.stopme()

##############################################
    def Hochladen(self, *parameter):
        u"Eine Seite bzw. Text aus der Editbox hochladen"
        mysite = wikipedia.getSite()
        upload=False
        ULminoredit = False
        if not self.bOnline:
            self.guiPrint(u"ACHTUNG! Nicht eingeloggt - Hochladen wurde abgebrochen.")
        else:
            self.guiPrint(u"--------\n%s - Der Hochladevorgang wird gestartet..." % self.logZeit())
            if len(parameter)==0:
                if self.bDebug: self.guiPrint(u"WA-Debug: Hochladen() mit 0 Parametern aufgerufen")
                SeitentitelUTF=self.EditBoxInhalt[len("Wikiseite:"):]
                if SeitentitelUTF[:1]=="'" and SeitentitelUTF[-1:]=="'": SeitentitelUTF=SeitentitelUTF[1:-1]
                ULtext = self.EditBox.get(1.0,END)
                ULcomment = ""
                SeitentitelUTF = askstring('Seitenname', 'Mit welchen Seitenamen (=Artikel) soll der Inhalt der Editbox hochgeladen werden ?', initialvalue=SeitentitelUTF)
                if ULcomment == "":
                    ULcomment = u"Mit dem Editor des WAbotTK von Hand erzeugt."
                    ULcomment = askstring('Kommentar', 'Soll dieser Kommentar auf der Seite "%s" benutzt werden ?' % SeitentitelUTF, initialvalue=ULcomment)
                upload=True
            elif len(parameter)==3:
                if self.bDebug: self.guiPrint(u"WA-Debug: Hochladen() mit 3 Parametern aufgerufen")
                SeitentitelUTF=parameter[0]
                ULtext = parameter[1]
                ULcomment = parameter[2]
                upload=True
            elif len(parameter)==4:
                if self.bDebug: self.guiPrint(u"WA-Debug: Hochladen() mit 4 Parametern aufgerufen")                
                SeitentitelUTF=parameter[0]
                ULtext = parameter[1]
                ULcomment = parameter[2]
                ULminoredit = parameter[3]
                upload=False ##True
            else:
                self.guiPrint(u"WA-Debug: Hochladen() mit '%d' Parametern aufgerufen. Nur 0,3,4 erlaubt." % len(parameter))

##            SeitentitelUTF = askstring('Seitenname', 'Mit welchen Seitenamen (=Artikel) soll der Inhalt der Editbox hochgeladen werden ?', initialvalue=SeitentitelUTF)
##            if ULcomment == "":
##                ULcomment = u"Mit dem Editor des WAbotTK von Hand erzeugt."
##                ULcomment = askstring('Kommentar', 'Soll dieser Kommentar auf der Seite "%s" benutzt werden ?' % SeitentitelUTF, initialvalue=ULcomment)
            pl = wikipedia.PageLink(mysite, SeitentitelUTF) #Pagelink erzeugen
            if not pl.exists(): 
                ULneuseite=True
            else:
                ULneuseite=False
################
            if upload and self.bDebug:
                auswahl = askyesno("Hochladen...", u"Soll die Seite '%s' mit dem Kommentar '%s' hochgeladen werden ?" % (SeitentitelUTF,ULcomment) )
                if not auswahl:  upload=False
            if upload:
                if self.bDebug: self.guiPrint(u"WA-Debug: upload=True")
                self.guiPrint(u"Die Seite '%s' wird mit dem Kommentar '%s' hochgeladen" % (SeitentitelUTF,ULcomment))
                try:    
                    #aus irgendeinem Grund funktioniert pl.put nicht
                    #pl.put(SeitentextUTF, comment=ULcommemt, minorEdit = False)
                    wikipedia.putPage(mysite, SeitentitelUTF, ULtext, ULcomment, watchArticle = False, minorEdit = ULminoredit, newPage =ULneuseite,token = None)
                    #pass
                except Uploadfehler:
                    self.guiPrint(u"%s - Es hat einen Unicodefehler beim Uploadversuch gegeben." % self.logZeit())
                    showerror("Uploadfehler!", u"Es hat einen Unicodefehler beim Uploadversuch gegeben. '%s' konnte nicht hochgeladen werden!." % SeitentitelUTF)
                except UnicodeDecodeError:   
                    self.guiPrint(u"%s - Es hat einen Unicodefehler beim Uploadversuch gegeben." % self.logZeit())
                    showerror("UnicodeDecodeError!", u"Es hat einen Unicodefehler beim Uploadversuch gegeben. '%s' konnte nicht hochgeladen werden!." % SeitentitelUTF)
                else:
                    self.guiPrint(u"Upload von '%s' hat funktioniert." % SeitentitelUTF)
            else:
                self.guiPrint(u"%s - Upload von '%s' wurde aus irgendwelchen Gründen nicht zugelassen (Upload=False)." % (self.logZeit(), SeitentitelUTF))
        wikipedia.stopme()            
            
    def SkriptUL(self):
        u"""Multiupload-Skript für Wiki Aventurica = mehrere Seiten in einem Rutisch hochladen.
        notwendiges Format der Textdatei :
        - Trennzeile muss so aussehen: '###mediawiki###Seitenname###Kommentar'
                Dabei ist
                 -Seitenname z.B. 'Publikationen:Egal was auch immer'
                 -Kommentar ist optional und wird dann statt des Standardkommentars ausgegeben
                  z.B. '###mediawiki###Sandkasten###kleine Änderungen von BenutzerX'
                 -wird kein Kommentar angegeben, kommt der Standardkommentar
                   'Roboted: Neu erzeugt durch ' + config.username
        - Seperate Letzte Zeile: '###mediawiki###MediawikiMultiuploadEnde'   """

        self.Dateiname=ur"c:\temp\ " #pfad allein reicht
        #self.Dateiname=r"c:\temp\DSAwiki-botsammler.wiki.txt"
        self.Dateiname=askopenfilename(defaultextension='*.txt',
                                       filetypes=[('Alle Dateien','*.*'),('Textdateien','*.txt'), ('Wikidateien','*.wiki.txt')],
                                       initialfile=self.Dateiname)
        if self.bDebug: self.guiPrint(u"Der Name der gewählten Datei ist :%s" % self.Dateiname)
        self.DateiEinlesen(self.Dateiname) #gleich in die EditBox einlesen
#todo: Abfrage und Zeit zur Bearbeitung lassen, eventuell mit Timeout 
        Seitentitel, Seitentext,Kommentar = "","",""  #alles Initialisieren
        SeitentitelAlt,KommentarAlt, SeitentextAlt="","",""
        Seitegefunden = False
        try:
            fUL = open(self.Dateiname, "r")
        except IOError:
            self.guiPrint(u"%s - Es ist ein IOfehler bei Datei %s aufgetreten." % (self.logZeit(), self.Dateiname))
        else:
            for ULzeile in fUL.readlines():
                #Die Datei muss mit "###mediawiki###Seitenname(###Kommentar)" beginnen
                #und mit "##mediawiki###MediawikiMultiuploadEnde" enden
                if ULzeile.startswith("###mediawiki###"): #Zeile mit Meta-Information
                    teile = ULzeile.split("###")
                    #print "DBUG:"+len(teile),"1:'"+teile[0]+"' 2:'"+teile[1]+"' 3:'"+teile[2]+"' 4:'"+teile[3]+"'"
                    if len(teile)==4: Kommentar=teile[3]  
                    if len(teile)>=3: SeitentitelNeu=teile[2]
                    SeitentitelAltUTF=self.umwandeln(SeitentitelAlt, "utf-8")
                    print "-->SeitentitelAlt='"+SeitentitelAlt+"'"
                    if SeitentitelAlt != "": # Beim 1. Durchgang Uberspringen
                        if SeitentitelAlt.startswith("MediawikiMultiuploadEnde"):
  ##                          wikipedia.stopme()
                            break #Upload beenden
                        if self.bDebug: self.guiPrint(u"Seitentitel='%s'" % SeitentitelAlt)

                        #Kategorie anhängen
                        SeitentextUTF=self.umwandeln(Seitentext, "utf-8")
                        try:
                            SeitentextUTF+=u"\n[[Kategorie:Roboted]]"
                        except UnicodeDecodeError:
                            self.guiPrint(u"UnicodeDecodeError bei Seitentext")
                        else:
                            pass
                        KommentarAltUTF=self.umwandeln(KommentarAlt, "utf-8")
                        if KommentarAltUTF.endswith("\n"): KommentarAltUTF=KommentarAltUTF[:-len(u"\n")]
                        self.Hochladen(SeitentitelAltUTF,SeitentextUTF,KommentarAltUTF)
                        #self.Hochladen(SeitentitelAlt,SeitentextAlt,KommentarAlt)
                        #except:
                        #    self.guiPrint(u"Fehler beim Hochladen aufgetreten")
                    else:
                        print "-->SeitentitelAlt ist leer"                        
                    ##nächste Seite vorbereiten
                    SeitentitelAlt=SeitentitelNeu
                    KommentarAlt=Kommentar
                    Seitentext = ""
                    SeitentitelAlt = SeitentitelAlt.replace(" ", "_") # Leerzeichen mit Unterstrichen ersetzen
                else:    #normale Zeile
                    Seitentext = Seitentext + ULzeile
            else:
                fUL.close() #Nach dem Ende der for-Schleife Datei schliessen
        if Seitegefunden==False:
            if SeitentitelAlt!="":
                self.guiPrint(u"%s- Die Datei wurde vollständig abgearbeitet.\n-------" % self.logZeit())
                print self.logZeit(),"-------------------" #Damit man in der Shell einen Abstandshalter hat
            else:
                self.guiPrint(u"%s - Es gab vermutlich Probleme mit dem Format der Datei oder die Datei existiert gar nicht." % self.logZeit())

#Das GUI für das Skript
    def guiBotErsetzenSkript(self):
        u"""Text im Wiki durch Aufruf von replace.py/replaceOOP.py ersetzen"""
        sSeitenname = u"Sandkasten"
        sAlt = u"Gruss"
        sNeu = u"Gruss\n\n==test==\ntest ~~~~" #Das haut leider nicht hin
        sNeu = u"""Gruss

==test==
test ~~~~""" #mal sehen ob das klappt
        
##        sSeitenname=askstring('Seitenname', 'Bitte eingeben, in welcher Seite Text ersetzt werden soll:', initialvalue=sSeitenname)
##        sAlt=askstring('Schritt 1 von 2: Was soll ersetzt werden (alter Text)?',
##                       'Bitte eingeben, welcher Text ersetzt werden soll:', initialvalue=sAlt)
##        sNeu=askstring('Schritt 2 von 2: Durch was soll ersetzt werden (neuer Text)?',
##                       'Bitte eingeben, welcher Text %s ersetzen soll:' % sAlt, initialvalue=sNeu)

        self.feReplace = Tk()
        fbreite,fhoehe = 280,300
        self.feReplace.geometry(str(fbreite)+"x"+str(fhoehe)+"+1+1")
        self.feReplace.title(u"Parameterabfrage für das Replace-Skript")

        self.frSeitenname = Frame(self.feReplace)
        laSeitenname = Label(self.frSeitenname, text= u"Seitenname (=Artikel) in der Wiki Aventurica:")
        laSeitenname.pack(side=TOP)
        self.eSeitenname = Entry(self.frSeitenname, bd="3", font = ("Times New Roman", 11))
        self.eSeitenname.pack(side=TOP, fill=BOTH, expand=1)
        self.frSeitenname.pack(side=TOP)

        self.frAlttext = Frame(self.feReplace)
        laAlttext = Label(self.frAlttext, text= u"Diesen Text:")
        laAlttext.pack(side=TOP)
        self.tAlttext = ScrolledText(self.frAlttext, height = 5, width = 40, background="#f7A7A7",
                                fg = "black", font = ("Times New Roman", 11))
        self.tAlttext.pack(side=TOP, expand=1)
        self.frAlttext.pack(side=TOP)

        self.frNeutext = Frame(self.feReplace)
        laNeutext = Label(self.frNeutext, text= u"Ersetzen durch:")
        laNeutext.pack(side=TOP)
        self.tNeutext = ScrolledText(self.frNeutext, height = 5, width = 40, background="#00F7A7",
                                fg = "black", font = ("Times New Roman", 11))
        self.tNeutext.pack(side=TOP, fill=BOTH, expand=1)
        self.frNeutext.pack(side=TOP)

        buStart = Button(self.frNeutext, text='Replace Starten', command=self.botErsetzSkript)
        buStart.pack(side=LEFT, fill=X)
        buBeenden = Button(self.frNeutext, text='Beenden', command=self.feReplace.destroy)
        ##command=self.feReplace.quit beendet das gesamte GUI statt nur dieses Fenster...
        buBeenden.pack(side=RIGHT, fill=X)

        self.eSeitenname.insert(END,sSeitenname)
        self.tAlttext.insert(END,sAlt)
        self.tNeutext.insert(END,sNeu)
        
    def botErsetzSkript(self):
        #das funktioniert nur, wenn das Skript Parameter annimmt und nicht sofort startet
        Ergebnis1 = "-page:" + self.eSeitenname.get()
        Ergebnis2 = "Alt: '" + self.tAlttext.get(1.0,END)
        Ergebnis3 = "' Neu:'" + self.tNeutext.get(1.0,END) + "'"
        Ergebnis=Ergebnis1+Ergebnis2+Ergebnis3
        self.guiPrint(u"\nErsetzskript hätte diese Parameter verwendet: '%s' " % Ergebnis)
        try: import replaceOOP
        except ImportError:
            nachricht=u"Das erforderliche Skript 'replaceOOP.py' ist nicht installiert.\nBitte aus dem Wiki ins Robotpaket-Verzeichnis kopieren."
            self.guiPrint(u"%s - %s" % (self.logZeit(), nachricht))
            showwarning("Skript fehlt!", nachricht)
        else:
            #replaceOOP.main(["",Ergebnis1,Ergebnis2,Ergebnis3])
            replaceOOP.main("",Ergebnis1,Ergebnis2,Ergebnis3) 

    def VerbindungsTestThread(self):
        thread.start_new_thread(self.VerbindungsTest,())        
    def VerbindungsTest(self):
        """ mit einem Seitenaufruf feststellen, ob wir online sind."""
        mysite = wikipedia.getSite()
        grund=""
        try: test=wikipedia.checkLogin()
        except IOError, grund:
            pass            
        else:            
            if test:
                self.guiPrint(u"%s: Wir sind eingeloggt auf '%s'." % (self.logZeit(),mysite.hostname() ))
                Statuswert.setzen(u"Online - auf Wiki.dsa4.de unter dem Benutzernamen: '%s'" % config.username)
                Statuswert.online(config.username)
                self.bOnline = True
            else:
                self.guiPrint(u"%s: Nicht einloggt auf '%s' %s" % (self.logZeit(),mysite.hostname(),grund ))
                Statuswert.setzen(u"-- NICHT Online -- %s" %grund)
                Statuswert.offline()
                self.bOnline = False
                global soundOK
                if soundOK: winsound.PlaySound('SystemAsterisk', winsound.SND_ALIAS)
                else: bell()
            wikipedia.stopme()
        
    def LoginFunktion(self):
        """ Login.py von Pywikipediabot übernommen und leicht angepasst
        Es wird u.A. auf TK zurückgegriffen und kein getpass verwendet
        Die config wird besser ausglesen, mit einem Tonsignal wird eine Abfragebox angekündigt.
        Leider müßte login.py erst OOPisiert werden, damit es als Modul importiert werden könnte.
        """
        site = wikipedia.getSite()
        wikipedia.output(u"%s: Anmelden bei %s" % (self.logZeit(),site.hostname() ))
        self.guiPrint(u"%s: Anmelden bei %s" % (self.logZeit(),site.hostname() ))
        Statuswert.setzen(u"Einloggen wurde gestartet ... (Bitte auf die Ausgabe in der Shell achten!)")

        global soundOK
        self.sPassword = ''
        self.sUsername = config.username
        if self.sUsername == '':
            if soundOK: winsound.PlaySound('SystemAsterisk', winsound.SND_ALIAS)
            else: bell()
            self.sUsername = wikipedia.input(u'username:', encode = True)
        else:
            if self.bDebug: self.guiPrint(u"%s - Benutzername '%s' konnte von user-config.py geladen werden." % (self.logZeit(), self.sUsername))
        try:
             self.sPassword = config.password
        except AttributeError:
            if self.bDebug: self.guiPrint(u"PW konnte nicht aus der user-config.py gelesen werden.")
        else:
            self.guiPrint(u"Kennwort konnte aus der Konfiguration gelesen werden.")
        dummy=PasswortAbfrage()
        if self.sPassword == '':
            if soundOK: winsound.PlaySound('SystemAsterisk', winsound.SND_ALIAS)
            else: bell()
            self.sPassword=askstring('Kennworteingabe', 'Bitte Kennwort eingeben:', initialvalue=self.sPassword)

        # Convert the password from the encoding your shell uses to the one your wiki
        # uses, via Unicode. This is the same as wikipedia.input() does with the 
        # username, but input() uses raw_input() instead of getpass().
        self.sPassword = unicode(self.sPassword, config.console_encoding)
        self.sPassword = self.sPassword.encode(wikipedia.myencoding())
        # I hope this doesn't need translation
        data = {"wpName": self.sUsername,
                "wpPassword": self.sPassword,
                "wpLoginattempt": "Aanmelden & Inschrijven",
                "wpRemember": str(int(bool(True)))}
        data = wikipedia.urlencode(data.items())

        headers = {"Content-type": "application/x-www-form-urlencoded", 
                   "User-agent": "RobHooftWikiRobot/1.01wa"} #config.Useragent}
        if self.bDebug: self.guiPrint(u"site.hostname()='%s'" % site.hostname() )
        conn = httplib.HTTPConnection(site.hostname())
        pagename = site.login_address()
        try:
            conn.request("POST", pagename, data, headers)
        except:
            self.guiPrint(u"%s - Fehler bei der Verbindungsaufnahme" % self.logZeit())
            conn.close()
            Statuswert.setzen(u" -=- NICHT Online -=- Fehler bei Verbindungsaufnahme.")
            Statuswert.offline()
        else:    
            self.guiPrint(u"Verbindung wurde erfolgreich hergestellt.... jetzt noch einloggen...")
            try:
                response = conn.getresponse()
            except httplib.ResponseNotReady:
                self.guiPrint(u"Fehler bei der Verbindungsaufnahme")
                conn.close()
                Statuswert.setzen(u" -=- NICHT Online -=- Fehler bei Verbindungsaufnahme.")
                Statuswert.offline()
            else:
                data = response.read()
                conn.close()
                status=response.status
                if self.bDebug: self.guiPrint(u"----{\nWA-Debug: response.statusPROX =%s " % status)
                if self.bDebug: self.guiPrint(u"WA-Debug: response.reason=%s" % response.reason)
                if "Fehler bei der Anmeldung:" in data:
                    self.guiPrint(u"%s- Es gab einen Fehler bei der Anmeldung! Es folgt der dump von data:" % self.logZeit())
                    try:
                        self.guiPrint(u"%s" % data)
                    except UnicodeDecodeError:
                        self.guiPrint(u"UnicodeDecodeError: Konnte die Daten leider nicht ausgeben")
                if self.bDebug: self.guiPrint(u"}----")
                n=0
                msg=response.msg
                Reat=re.compile(': (.*?);')
                L = []
                #self.guiPrint(u"%s" %repr(msg.getallmatchingheaders('set-cookie')))
                for eat in msg.getallmatchingheaders('set-cookie'):
                    m=Reat.search(eat)
                    if m:
                        #n += 1
                        L.append(m.group(1))

                if len(L) == 4: #n==4: 
                    self.guiPrint(u"%s - Der Bot sollte nun online sein (da 4 Cookies gesetzt werden konnten)." % self.logZeit())
                    Statuswert.setzen(u"Online - auf Wiki.dsa4.de unter dem Benutzernamen: '%s'" % config.username)
                    self.bOnline = True
                    Statuswert.online(config.username)
                else:
                    self.guiPrint(u"%s- Es konnten nur '%s' Cookies (anstatt 4) gelesen werden.\nIrgendwas ging wohl schief. Eventuell falsches Kennwort?" % (self.logZeit(), n))
                    Statuswert.setzen(u" -=- NICHT Online -=- ")
                    Statuswert.offline()
                    self.bOnline = False
        self.guiPrint(u"--------")
        wikipedia.stopme()
        auswahl = askyesno(u"Logbucheintrag?", u"Soll sogleich der Eintrag im Robot-Logbuch erstellt werden?" )
        if auswahl:
            self.RobotLogErweitern()

##########################
#ab hier alle Skripte die noch über die Konsole gesteuert werden

    def botKonsolenskript(self,*parameter):
        u"""eine neue Shell mit eigenem Thread starten und dort ein Skript
        ausführen, als wäre es per Hand gestartet worden
        todo: OS-Erkennung und entsprechende Startparameter"""
        if len(parameter)!=0: args=parameter[0]
        else: args=""
        aufrufNachOS = u"command /k python "+args #Das gilt jedenfalls für (manche) Win32
        #aufrufNachOS = "cmd python "+args #das für andere
        #aufrufNachOS = "bash -c 'python "+args+"'" #unter Linux
        showinfo(u"Skripte über Konsole starten",
                 u"Bitte sicherstellen, dass python in einer Konsole gestartet werden kann (alle Umgebungsvariablen/Pfade gesetzt sind). Ansonsten passiert nürlich gar nichts.")
        self.guiPrint(u"%s - Das folgende Robotskript wurde gestartet:%s" % (self.logZeit(), aufrufNachOS))
        thread.start_new_thread(os.system,((aufrufNachOS),))        
    def botLoginKonsole(self):
        self.botKonsolenskript("login.py")
    def botReplaceKonsole(self):
        self.botKonsolenskript("replace.py")
    def botRedirectDouble(self):
        self.botKonsolenskript("redirect.py double")
    def botRedirectBroken(self):
        self.botKonsolenskript("redirect.py broken")
    def botCheckExtern(self):
        parameter1=u"-start:"
        parameter = askstring(u'Parameter für check_extern.py',
                              u"""Bitte sichergehen, dass python in einer Konsole gestartet werden kann (alle Umgebungsvariablen/Pfade gesetzt sind). Ansonsten passiert nürlich gar nichts.

                              Mit dem Parameter '-start:SEITENNAME' kann die Abfrage von Spezial:Allpages verkürzt werden.
                              In der Datei 'check_extern.log' kann das Ergebnis zusätzlich zur Bildschirmausgabe entnommen werden.""",
                              initialvalue=parameter1)
        if parameter==parameter1: parameter=""
        self.botKonsolenskript("check_extern.py "+parameter)
    def botTouchAll(self):
        parameter1=u"-start:!"
        parameter = askstring(u'Parameter für check_extern.py',
                              u"""Bitte sichergehen, dass python in einer Konsole gestartet werden kann (alle Umgebungsvariablen/Pfade gesetzt sind). Ansonsten passiert nürlich gar nichts.

                              Mit dem Parameter '-start:SEITENNAME!' kann die Abfrage von Spezial:Allpages verkürzt werden.
                              In der Datei 'check_extern.log' kann das Ergebnis zusätzlich zur Bildschirmausgabe entnommen werden.""",
                              initialvalue=parameter1)
        if parameter==parameter1:
            parameter=""
        elif parameter[-1:]!="!" and parameter[:7]=="-start:":
            parameter+=u"!"
        else:
            parameter=""
        self.botKonsolenskript("touchall.py "+parameter)
        
####################################
# eigene Klassen ab hier
####################################
class PasswortAbfrage:
    def __init__(self):
        self.fePWFenster = Tk()
        self.fePWFenster.title(u"Abfrage Username/Kennwort")
        
        self.frRahmen = Frame(self.fePWFenster, relief='ridge', borderwidth=2)
        self.frRahmen.grid()

        self.laBenutzerPic = Label(self.frRahmen, bitmap="questhead")
        self.laBenutzername = Label(self.frRahmen,  width=20, height=1,
                                    text=u"Benutzername:")
        self.enBenutzername = Entry(self.frRahmen) #, textvariable=self.tkUsername)
        self.laPasswPic = Label(self.frRahmen, bitmap="info")
        self.laPasswort = Label(self.frRahmen, width=20, height=1,
                                text=u"Passwort (verdeckt):")
        self.enPasswort = Entry(self.frRahmen, show='*') #, textvariable=self.tkPW)
        self.laBotlog = Label(self.frRahmen, width=50, height=1,
                              text=u"Text der im Robotlog erscheinen soll (leer=nichts):")
        self.enBotlog = Entry(self.frRahmen, width=50) #, textvariable=self.tkUsername)
        self.buLoginButton = Button(self.frRahmen, text='Anmelden', bg="green", command=self.auswerten)
        self.buAbbruchButton = Button(self.frRahmen, text='Abbrechen', bg="red", command=self.abbrechen)

        self.laBenutzerPic.grid(row=0, sticky="W", column=0)
        self.laBenutzername.grid(row=0, sticky="W", column=1)
        self.enBenutzername.grid(row=0, sticky="E", column=2)
        self.laPasswPic.grid(row=1, sticky="W", column=0)
        self.laPasswort.grid(row=1, sticky="W", column=1)
        self.enPasswort.grid(row=1, sticky="E", column=2)
        self.laBotlog.grid(row=2, column=0, columnspan=3)
        self.enBotlog.grid(row=3, column=0, columnspan=3)
        self.buLoginButton.grid(row=4, column=1)
        self.buAbbruchButton.grid(row=4, column=2)

        #hoehe,breite = self.fePWFenster.winfo_height(), self.fePWFenster.winfo_width()
        self.fePWFenster.geometry(str(370)+"x"+str(150)+"+"+str(10)+"+"+str(10))

        self.enBenutzername.delete("0",END)
        self.enBenutzername.insert("0",WAinstanz.sUsername)
        self.enPasswort.delete("0",END)
        self.enPasswort.insert("0",WAinstanz.sPassword)
        self.enBotlog.delete("0",END)
        self.enBotlog.insert("0",u"unkategorisierte Seiten +Kategorie:xy")
        self.fePWFenster.mainloop()

    def auswerten(self):
        uname=self.enBenutzername.get()
        pword = self.enPasswort.get()
        robolog = self.enBotlog.get()
        if uname!= "": WAinstanz.sUsername = uname
        if pword!= "": WAinstanz.sPassword= pword
        if robolog!= "": WAinstanz.robotLog = robolog
        self.beenden()
    def abbrechen(self):
        pass
        self.beenden()
    def beenden(self):
        self.fePWFenster.quit()
        try:
            self.fePWFenster.destroy() #scheinbar reicht quit() nicht allein
        except:
            pass
        ##quit allein hat nicht funktioniert?

class Nachricht:
    def __init__(self):
        pass

    def write(self, *text):
        pass
    
    def stdprint(self, *text):
        sicherung=sys.stdout
        sys.stdout=sys.__stdout__
        for i in text:
            print i,
        print
        sys.stdout=sicherung
        
class Statusbar(Frame):
    def __init__(self, Hauptschluessel):
        Frame.__init__(self,Hauptschluessel)
        self.laOnline=Label(self, bd=1, relief=SUNKEN, anchor=W)
        self.laOnline.pack(side=LEFT) #side=BOTTOM)
        self.offline()
        self.laStatustext=Label(self, bd=1, relief=SUNKEN, anchor=W)
        self.laStatustext.pack(fill=X)
    def setzen(self, textinhalt):
        "Inhalt der Stausleiste verändern"
        self.laStatustext.config(text=textinhalt)
        self.laStatustext.update_idletasks()
    def lesen(self):
        "Inhalt der Stausleiste zurückgeben"
        return self.laStatustext.cget("text") 
    def loeschen(self):
        "Inhalt der Stausleiste löschen"
        self.laStatustext.config(text='')
        self.laStatustext.update_idletasks()
    def online(self, textinhalt=""):
        if textinhalt!="": textinhalt = u" unter:"+textinhalt
        self.laOnline.config(text=u"-*online*-", fg="black", bg="green")
        self.laOnline.update_idletasks()
    def offline(self, textinhalt=""):
        self.laOnline.config(text=u" -offline- ", fg="white", bg="red")
        self.laOnline.update_idletasks()

#Eigene Fehlerroutine
class Uploadfehler:
    value = "Problem beim Upload, vermutl. Unicodeproblem"
    def __str__(self):
        return self.value

def installationsfehler(fehlt):
    encoding=sys.getdefaultencoding()
    pfad = os.path.dirname(os.path.abspath(sys.argv[0])) #auf win32 abspath notwendig
    nachricht=u""
    unvollst=False
    if fehlt: nachricht =u"""Es sind nicht alle notwendigen Skripte installiert. So kann das GUI nicht funktionieren."""
    nachricht+=u"\nBitte die folgenden Anpassungen durchführen:"""
    try: fH=open(os.path.normpath(pfad+"/wikipedia.py"),"r")
    except IOError:
        nachricht+=u"\n - das Pywikipediabotpaket wurde nicht installiert ODER der WAbotTK befindet sich nicht im selben Verzeichnis"
        unvollst=True
    else: fH.close()
    try: fH=open(os.path.normpath(pfad+"/families/wikiaventurica_family.py"),"r")
    except IOError:
        nachricht+=u"\n - das Pywikipediabotpaket wurde nicht auf das Wiki Aventurica angepasst ODER der WAbotTK befindet sich nicht im selben Verzeichnis"
        unvollst=True
    else: fH.close()
    try: fH=open(os.path.normpath(pfad+"/user-config.py"),"r")
    except IOError:
        nachricht+=u"\n - die Datei 'user-config.py' muss noch erstellt werden"
        unvollst=True
    else: fH.close()
    if encoding.upper()=="ASCII":
        nachricht+= u"\n - das Defaultencoding ist auf ASCII statt auf utf-8 eingestellt"
        unvollst=True
    nachricht+=u"\nAlle Detailinformationen zu den notwendigen Änderungen können auf der folgenden Seite nachgelesen werden."
    nachricht+=u"\n --> http://dsa4.de/wiki/index.php?title=Wiki_Aventurica:Robots"
    if unvollst: showinfo("Installationsfehler!", nachricht)
def main(fehlt):
    global Statuswert, WAinstanz
    encoding=sys.getdefaultencoding()
    Hauptfenster = Tk()
    Statuswert = Statusbar(Hauptfenster)
    Statuswert.pack(side=BOTTOM, fill=X)
    Statuswert.setzen(u"Bereit! Bitte oben 'einloggen' wählen...")
    WAinstanz = WAbotTK(Hauptfenster)    

    WAinstanz.Nachricht(ur"""Wilkommen im WAbotTk, dem GUI für die Robotskripte zum Wiki Aventurica (http://wiki.dsa4.de).
Bitte das Menü benutzen."""+__version__+" - Defaultencoding="+sys.getdefaultencoding()+"\n----------------------\n")

    if fehlt: installationsfehler(True)
    else:
        arg=""
        for arg in sys.argv[1:]:
            pass
        if arg:
            WAinstanz.guiPrint(u"""Bisher werden noch keine Parameter beim Programmaufruf ausgewertet.
 Wenn du allerdings eine gute Idee hast, dann schreibe sie doch im Wiki auf die Seite
 http://dsa4.de/wiki/index.php?title=Wiki_Aventurica_Diskussion:Robots/WAbotTK_ein_GUI_f%FCr_die_Robotskripte""")
        if encoding.upper()=="ASCII":
            WAinstanz.guiPrint(u"""Das Defaultencoding ist auf ASCII gestellt! Daher werden zahlreiche Funktionen UnicodeEncodeError hervorrufen!
Bitte entsprechend anpassen (siehe Hilfe).""")
        installationsfehler(False)
        Hauptfenster.mainloop()
    if WAinstanz.Hauptfenster:
        try:
            WAinstanz.Hauptfenster.quit()
        except TclError:
            pass
    
if __name__=="__main__":
    global docstring, backupStdout, backupStderr, Statuswert, WAinstanz
    docstring = __doc__ #nur einmal Tipparbeit
    #print docstring
#Standardausgabe umleiten
##    backupStdout, backupStderr = sys.stdout,sys.stderr

    if tkinterFehlt:
        print "Das Tkinter-Modul ist nicht installiert. Normalerweise ist das bei Python 2.xx dabei...."
        print "Irgendwie muss Python also falsch installiert sein. Das Robot-GUI kann deswegen nicht gestartet werden."
    else:
        main(botPaketFehlt)

#Ausgabe wieder auf Standard setzen        
##    sys.stdout,sys.stderr = backupStdout, backupStderr


Dann mal viel Erfolg mit dem GUI und bitte bei der Entwicklung mithelfen.

Historie[Bearbeiten]

  • Sämtliche print-Aufrufe sollten besser durch die Funktion self.guiPrint(u"text") bzw. self.guiPrint(u"text %s" %variable) durchgeführt werden.
V0.71 bis V0.73
  • Automatisches Scrollen funktioniert inzwischen ab V0.71
  • Es kann eine Seite aus dem Wiki eingelesen und bearbeitet, dann hochgeladen oder abgespeichert werden
    Schon jetzt sehr schick: Mit der Suche ein Wortschnippsel im ganzen WIKI-Source farbig hervorheben
  • Die Konfig kann bearbeitet (aber noch nicht gespeichert) werden
  • es ist ein GUI-Modul für ReplaceOOP.py eingebaut mit DIFF-ähnlicher Aufteilung
  • Die Aufteilung ist etwas schöner geworden
  • Keine Knöpfe links mehr zur Steuerung, stattdessen ein Menü
  • Der Verbindungstest funktioniert jetzt wieder
  • Unter Linux kann man den WAbotTK auch aus dem IDLE starten, unter Windows gibt es einen Fehler, da bitte die Syntax python WabotTK.py benutzen.
Neu in 0.74 
  • Der Abstand zwischen den Fenstern kann mit einem kleinen roten Kästchen verändert werden
  • Es gibt ein rudimentäres Syntaxhighlighting in der EditBox für Wikitags (die wichtigsten sind schon erfasst) Damit können dann abgerufene oder lokal geladene Dateien bearbeitet werden.
  • Es kann eine Datei / die userconfig eingelesen und bearbeitet werden
  • es wurden zahlreiche kleinere Fehler ausgemerzt

V0.75 nicht veröffentlicht

Neu in V0.76 
  • Syntaxhighlighting ist jetzt flexibel programmiert und sehr einfach anpassbar, es fehlt nur noch das benutzerdefinierte Festlegen+Abspeichern
  • Die Editbox kann jetzt prima als Wiki-Editor benutzt werden
  • Aus dem Menü können Konsolenskripte gestartet werden, gelöst per multithreading. Sie sind sehr leicht erweiterbar. Auf diese Weise ließen sich die meisten Skripte dann doch zumindest per Maus starten, wenn dann auch die Bedienung in der Konsole erfolgen muss...
  • zahlreiche kleine Bugfixes
  • Multiuploadskript umgeschrieben, allerdings kaum getestet
  • Online-Indikator unten links in der Statuszeile in rot/grün eingebaut
Neu in V0.77 
  • zahlreiche kleinere Bugfixes, Speichern funktioniert jetzt wieder
  • Mediawikifehler können korrigiert werden
  • eine automatische Eintragung für Wiki_Aventurica:Roboteinsatz_Logfile ist eingebaut, interaktiv zu bedienen
  • die Routine für die Bearbeitung von Belohnungen für Abenteuer ist als Gerüst fertig, was noch fehlt ist der eigentliche Code ;-)
  • das Menü wurde überarbeitet, kein "Tearoff" mehr, inaktive Punkte sind disabled, neue Untermenüs
  • Konsolenskripte etwas vereinfacht, Todo: Betriebssystemerkennung für den Aufruf der Kommandozeile
Neu in V.78 
  • Anfängerfreundliche Abfrage, ob und welche Anpassungen vorgenommen wurden, mit ausführlichen Hinweisen, was zu tun ist. Das GUI ist jetzt auch startbar, wenn nichts anderes installiert wurde.
  • Das GUI startet jetzt auch, wenn der Benutzer die Anleitung nicht gelesen und folglich das Robotpaket gar nicht installiert hat ;-)
  • Ersetzfunktion (Search & Replace), die auch gesteuert werden kann, leider noch nicht interaktiv
  • darauf aufbauend ein UTF-Umlaute-Filter
  • Routine, die automatisch im Robotlogfile Eintragungen vornimmt, aber noch interaktiv angepasst werden kann, bevor die Daten online gestellt werden
  • bell() bei Fehlermeldungen alternativ zu winsound
  • Vorbereitung zur Umleitung von sys.stdout, sys.stdin auf self.guiPrint()
  • teilweise erste Sicherheitsabfragen

V0.79: nicht veröffentlicht, da teilweise buggy

Neu in V0.80 
  • erste Versuche mit Multithreading, damit das GUI nicht einfriert, während eine Routine abgearbeitet wird, funzt noch nicht so recht: ein gestarteter Thread führt zum restlosen Einfrieren.
  • etwas Ordnung im Code geschaffen, Routinen verschoben, nunmehr überflüssiges entfernt, etc.
  • Belohnungen2Tabelle eingebaut als Aufruf von bel2tab.py - Parser für Belohnungen für Abenteuer funktioniert
  • Wikifizierungsfunktion eingebaut, Text wird anhand eines Dictionary wikifiziert (=verlinkt und formatiert), leider noch nicht interaktiv steuerbar
  • Eurosymbole machten noch Ärger, Umwandlungsroutinen verbessert UnicodeDecodeErrors sollten jetzt endgültig behoben sein, Problem bei wikipedia.forSite() gefunden, Workaround auf der Anpassungsseite
  • ein paar Messageboxes und Sicherheitsabfragen zusätzlich, Logangaben mit Uhrzeit
  • Autoscroll der Nachrichtenbox springt jetzt immer zum Ende, statt nur eine Seite weit
  • bei der Hochladefunktion fehlte die Abfrage, dann konnte es natürlich nicht funktionieren ;-)
  • vorbereitet für automatisches Update durch selbstmodifzierenden Code unter Berücksichtigung von MD5-Checksumme der bestehenden Datei