class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.notebook_1 = wx.Notebook(self, -1, style=wx.NB_BOTTOM)
        self.notebook_1_pane_2 = wx.Panel(self.notebook_1, -1)
        self.notebook_1_pane_1 = wx.Panel(self.notebook_1, -1)
        self.panel_1 = wx.Panel(self, -1)
        
        # Menu Bar
        self.menuBar = wx.MenuBar()

        menu = wx.Menu()
        menu.Append(ITEM_BATCH_EXPORT_ID, u"für alle Semestergruppen und Dozenten exportieren", "", wx.ITEM_NORMAL)
        self.menuBar.Append(menu, "Batch")

        menu = wx.Menu()
        menu.Append(ITEM_EUI_ID, "Elektrotechnik und Informatik", "", wx.ITEM_NORMAL)
        menu.Append(ITEM_EUI_LOAD_ID, "            -> direkt einlesen", "", wx.ITEM_NORMAL)
        menu.Append(ITEM_INF_ID, "Informatik", "", wx.ITEM_NORMAL)
        menu.Append(ITEM_INF_LOAD_ID, "            -> direkt einlesen", "", wx.ITEM_NORMAL)
        menu.AppendSeparator()
        menu.Append(ITEM_GOOGLE_CALENDAR_ID, "Google Calendar", "", wx.ITEM_NORMAL)
        menu.AppendSeparator()
        menu.Append(ITEM_RFC5545_ID, "iCalendar rfc5545", "", wx.ITEM_NORMAL)
        self.menuBar.Append(menu, "Links")

        menu = wx.Menu()
        menu.Append(ITEM_HELP_ID, "Anleitung", "", wx.ITEM_NORMAL)
        menu.Append(ITEM_GPL_ID, "GPL", "", wx.ITEM_NORMAL)
        menu.Append(ITEM_ABOUT_ID, "About", "", wx.ITEM_NORMAL)
        self.menuBar.Append(menu, "Hilfe")

        self.SetMenuBar(self.menuBar)

        # frame pane
        self.button_Load = wx.Button(self, BTN_LOAD_ID, "HAW-Kalender einlesen")
        self.button_Export = wx.Button(self, BTN_EXPORT_ID, "Termin-Auswahl als iCalendar exportieren")
        self.infoString = wx.StaticText(self.panel_1, TXT_INFO_STRING_ID, "      Bitte eine HAW-Kalender Textdatei einlesen                    ")
        self.treeCtrl_Stud = wx.TreeCtrl(self.notebook_1_pane_1, TREE_CTRL_STUD_ID, style=wx.TR_HIDE_ROOT|wx.TR_HAS_BUTTONS|wx.TR_NO_LINES|wx.TR_DEFAULT_STYLE|wx.SUNKEN_BORDER|wx.TR_MULTIPLE)
        self.treeCtrl_Doz = wx.TreeCtrl(self.notebook_1_pane_2, TREE_CTRL_DOZ_ID, style=wx.TR_HIDE_ROOT|wx.TR_HAS_BUTTONS|wx.TR_NO_LINES|wx.TR_DEFAULT_STYLE|wx.SUNKEN_BORDER|wx.TR_MULTIPLE)

        self.__doLayout()
        self.__doFrameBindings()
        self.__doMenuBindings()

        self.menuItem_AlleSemUndDoz = self.menuBar.FindItemById(ITEM_BATCH_EXPORT_ID)
        self.menuItem_AlleSemUndDoz.Enable(False)

        self.space = "      "

    def __doLayout(self):
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4.Add(self.button_Load, 0, 0, 0)
        sizer_4.Add(self.button_Export, 0, 0, 0)
        sizer_5.Add(self.infoString, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
        self.panel_1.SetSizer(sizer_5)
        sizer_4.Add(self.panel_1, 1, wx.EXPAND|wx.ALIGN_RIGHT, 0)
        sizer_1.Add(sizer_4, 0, 0, 0)
        sizer_2.Add(self.treeCtrl_Stud, 1, wx.EXPAND, 0)
        self.notebook_1_pane_1.SetSizer(sizer_2)
        sizer_3.Add(self.treeCtrl_Doz, 1, wx.EXPAND, 0)
        self.notebook_1_pane_2.SetSizer(sizer_3)
        self.notebook_1.AddPage(self.notebook_1_pane_1, "Studentensicht")
        self.notebook_1.AddPage(self.notebook_1_pane_2, "Dozentensicht")
        sizer_1.Add(self.notebook_1, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()

    def __doFrameBindings(self):
        self.button_Load.Bind(wx.EVT_BUTTON, self.onButton_Load)
        self.button_Export.Bind(wx.EVT_BUTTON, self.onButton_Export)
        self.button_Export.Disable()
        self.treeCtrl_Stud.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.onDoubleClick_Stud)
        self.treeCtrl_Doz.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.onDoubleClick_Doz)

    def __doMenuBindings(self):

        self.Bind(wx.EVT_MENU, self.onMenuItem_BatchStudUndDoz, id=ITEM_BATCH_EXPORT_ID)

        self.Bind(wx.EVT_MENU, self.onMenuItem_EuI, id=ITEM_EUI_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_EuI_load, id=ITEM_EUI_LOAD_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_Inf, id=ITEM_INF_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_Inf_load, id=ITEM_INF_LOAD_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_GoogleCalendar, id=ITEM_GOOGLE_CALENDAR_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_rfc5545, id=ITEM_RFC5545_ID)

        self.Bind(wx.EVT_MENU, self.onMenuItem_Anleitung, id=ITEM_HELP_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_GPL, id=ITEM_GPL_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_About, id=ITEM_ABOUT_ID)

    def onButton_Load(self, event):
        dlg = wx.FileDialog(self, "txt-Version des Semesterplans auswählen")
        dlg.SetWildcard("nur Textdateien (*.txt)|*.txt|alle Dateien|*")

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.ctrl = Controller(inFileName=path, outFileName=None)
            self.infoString.SetLabel(self.space + "HAW-Kalender: " + self.ctrl.getInfoString())

            self.fillTrees()

        dlg.Destroy()

        self.updateExportButton()
        self.menuItem_AlleSemUndDoz.Enable()

    def fillTrees(self):

        def fillTree(treeCtrl):
            font = wx.Font(12, wx.MODERN, wx.NORMAL, wx.NORMAL, False, u'Courier New')
            treeCtrl.SetFont(font)

            groups = sorted(self.ctrl.getKeys())
            treeCtrl.DeleteAllItems()
            rootName = "root"
            rootName_unicode = rootName.decode("utf-8")
            root = treeCtrl.AddRoot(rootName_unicode)
            for key in groups:
                key_unicode = key.decode("utf-8")
                parent = treeCtrl.AppendItem(root, key_unicode)
                veranstaltungen = sorted(self.ctrl.getVeranstaltungen(key))

                maxLen = len(reduce(lambda x,y: max(x,y, key=len), veranstaltungen))
                formatter = "{0:<" + str(maxLen+3) + "}"

                for veranstaltung in veranstaltungen:
                    leftAlignedVeranstaltung = formatter.format(veranstaltung)
                    #FIXME: dirty hack (a 'Ü' is represented in utf-8 by 2 byte)
                    if 'Ü' in leftAlignedVeranstaltung:
                        leftAlignedVeranstaltung += " "
                    s = leftAlignedVeranstaltung + self.ctrl.tryGetFullName(veranstaltung)
                    s_unicode = s.decode("utf-8")
                    treeCtrl.AppendItem(parent, s_unicode)

        self.ctrl.tupleKeyIndex = DOZENT
        fillTree(self.treeCtrl_Doz)

        self.ctrl.tupleKeyIndex = self.ctrl.optimalGruppenKeyIndex()
        fillTree(self.treeCtrl_Stud)

    def onButton_Export(self, event):
        style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT
        dlg = wx.FileDialog(self, message="iCalendar (.ics) speichern unter", style=style)
        dlg.SetWildcard("iCalendar-Dateien (*.ics)|*.ics")

        if dlg.ShowModal() == wx.ID_OK:

            path = dlg.GetPath()
            if not path.endswith(".ics"):
                path = path + ".ics"

            self.ctrl.setOutFileName(path)
            self.ctrl.writeIcalendar()

        dlg.Destroy()

    def onDoubleClick_Stud(self, wxTreeEvent):
        self.ctrl.tupleKeyIndex = self.ctrl.optimalGruppenKeyIndex()
        self.onDoubleClick(wxTreeEvent, self.treeCtrl_Stud)

    def onDoubleClick_Doz(self, wxTreeEvent):
        self.ctrl.tupleKeyIndex = DOZENT
        self.onDoubleClick(wxTreeEvent, self.treeCtrl_Doz)
        
    def onDoubleClick(self, wxTreeEvent, treeCtrl):
        itemId = wxTreeEvent.GetItem()

        text_unicode = treeCtrl.GetItemText(itemId)
        text_utf8 = text_unicode.encode("utf-8")

        isVeranstaltung = not treeCtrl.ItemHasChildren(itemId)

        if not isVeranstaltung:
            key = text_utf8
            veranstaltungen = self.ctrl.getVeranstaltungen(key)
            if self.groupFullSelected(key):
                self.ctrl.unselectVeranstaltungen(veranstaltungen)
            else:
                self.ctrl.selectVeranstaltungen(veranstaltungen)
        else:
            veranstaltung = text_utf8.split("   ")[0] #FIXME: dirty
            if veranstaltung in self.ctrl.selectedVeranstaltungen:
                    self.ctrl.selectedVeranstaltungen.remove(veranstaltung)
            else: 
                self.ctrl.selectedVeranstaltungen.add(veranstaltung)

        self.updateTrees()
        self.updateExportButton()

    def updateTrees(self):
        def updateTree(treeCtrl):
            for keyItemId in iterChildren(treeCtrl, treeCtrl.GetRootItem()):

                allSelected = True
                for veranstItemId in iterChildren(treeCtrl, keyItemId):

                    text_unicode = treeCtrl.GetItemText(veranstItemId)
                    veranstaltung = text_unicode.encode("utf-8").split("   ")[0] #FIXME: dirty

                    if not veranstaltung in self.ctrl.selectedVeranstaltungen:
                        treeCtrl.SetItemBold(veranstItemId, False)
                        allSelected = False
                    else:
                        treeCtrl.SetItemBold(veranstItemId)

                treeCtrl.SetItemBold(keyItemId, allSelected)

            treeCtrl.Refresh()

        updateTree(self.treeCtrl_Stud)
        updateTree(self.treeCtrl_Doz)

    def updateExportButton(self):
        if len(self.ctrl.selectedVeranstaltungen) > 0:
            self.button_Export.Enable()
        else:
            self.button_Export.Disable()

    def groupFullSelected(self, key):
        return (self.ctrl.selectedVeranstaltungen & set(self.ctrl.getVeranstaltungen(key)) == set(self.ctrl.getVeranstaltungen(key)))

    def onMenuItem_BatchStudUndDoz(self, event):

        dlg = wx.DirDialog(self, "Verzeichnis für Batch-Export auswählen")

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            dlg.Destroy()

            batchCtrl = copy.deepcopy(self.ctrl)

            dlg = RunningBatchExportDialog(parent=self,
                                           text="Batch-Export gestartet:\n\n",
                                           title="Batch-Export",
                                           ctrl=batchCtrl,
                                           path=path)
            dlg.ShowModal() 
            dlg.Destroy()

    def onMenuItem_EuI(self, event):
        webbrowser.open(STUNDENPLAN_SITE_EuI, autoraise=True)

    def onMenuItem_EuI_load(self, event):
        try:
            sys.stdin = urllib.urlopen(STUNDENPLAN_URL_EuI)
            self.ctrl = Controller(inFileName=None, outFileName=None)
            self.infoString.SetLabel(self.space + "HAW-Kalender: " + self.ctrl.getInfoString())
            self.fillTrees()

            self.updateExportButton()

            self.menuItem_AlleSemUndDoz.Enable()

        except IOError as e:
            print "Could not open EuI-url: " + str(e)

    def onMenuItem_Inf(self, event):
        webbrowser.open(STUNDENPLAN_SITE_Inf, autoraise=True)

    def onMenuItem_Inf_load(self, event):
        try:
            sys.stdin = urllib.urlopen(STUNDENPLAN_URL_Inf)
            self.ctrl = Controller(inFileName=None, outFileName=None)
            self.infoString.SetLabel(self.space + "HAW-Kalender: " + self.ctrl.getInfoString())
            self.fillTrees()

            self.updateExportButton()

            self.menuItem_AlleSemUndDoz.Enable()

        except IOError as e:
            print "Couldn't open Inf-url: " + str(e)

    def onMenuItem_GoogleCalendar(self, event):
        webbrowser.open("http://www.google.com/calendar", autoraise=True)

    def onMenuItem_rfc5545(self, event):
        webbrowser.open("http://tools.ietf.org/html/rfc5545/", autoraise=True)

    def onMenuItem_Anleitung(self, event):

        text_unicode = texts.anleitung.decode("utf-8")

        dlg = ScrollableDialog(None, text_unicode, title="Anleitung")
        dlg.ShowModal()
        dlg.Destroy()

    def onMenuItem_GPL(self, event):

        text = texts.gpl
        text = " " + text.replace("\n", "\n ")
        text_unicode = text.decode("utf-8")

        dlg = ScrollableDialog(self, text_unicode, title="GPL")
        dlg.ShowModal()
        dlg.Destroy()

    def onMenuItem_About(self, event):

        text = texts.version + "\n\n" + texts.homepage + "\n\n" + texts.about
        text_unicode = text.decode("utf-8")

        dlg = wx.MessageDialog(self, text_unicode, caption="About", style=wx.OK)
        dlg.ShowModal()
        dlg.Destroy()
class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.notebook_1 = wx.Notebook(self, -1, style=wx.NB_BOTTOM)
        self.notebook_1_pane_2 = wx.Panel(self.notebook_1, -1)
        self.notebook_1_pane_1 = wx.Panel(self.notebook_1, -1)
        self.panel_1 = wx.Panel(self, -1)

        # Menu Bar
        self.menuBar = wx.MenuBar()

        menu = wx.Menu()
        menu.Append(ITEM_BATCH_EXPORT_ID,
                    u"für alle Semestergruppen und Dozenten exportieren", "",
                    wx.ITEM_NORMAL)
        self.menuBar.Append(menu, "Batch")

        menu = wx.Menu()
        menu.Append(ITEM_EUI_ID, "Elektrotechnik und Informatik", "",
                    wx.ITEM_NORMAL)
        menu.Append(ITEM_EUI_LOAD_ID, "            -> direkt einlesen", "",
                    wx.ITEM_NORMAL)
        menu.Append(ITEM_INF_ID, "Informatik", "", wx.ITEM_NORMAL)
        menu.Append(ITEM_INF_LOAD_ID, "            -> direkt einlesen", "",
                    wx.ITEM_NORMAL)
        menu.AppendSeparator()
        menu.Append(ITEM_GOOGLE_CALENDAR_ID, "Google Calendar", "",
                    wx.ITEM_NORMAL)
        menu.AppendSeparator()
        menu.Append(ITEM_RFC5545_ID, "iCalendar rfc5545", "", wx.ITEM_NORMAL)
        self.menuBar.Append(menu, "Links")

        menu = wx.Menu()
        menu.Append(ITEM_HELP_ID, "Anleitung", "", wx.ITEM_NORMAL)
        menu.Append(ITEM_GPL_ID, "GPL", "", wx.ITEM_NORMAL)
        menu.Append(ITEM_ABOUT_ID, "About", "", wx.ITEM_NORMAL)
        self.menuBar.Append(menu, "Hilfe")

        self.SetMenuBar(self.menuBar)

        # frame pane
        self.button_Load = wx.Button(self, BTN_LOAD_ID,
                                     "HAW-Kalender einlesen")
        self.button_Export = wx.Button(
            self, BTN_EXPORT_ID, "Termin-Auswahl als iCalendar exportieren")
        self.infoString = wx.StaticText(
            self.panel_1, TXT_INFO_STRING_ID,
            "      Bitte eine HAW-Kalender Textdatei einlesen                    "
        )
        self.treeCtrl_Stud = wx.TreeCtrl(
            self.notebook_1_pane_1,
            TREE_CTRL_STUD_ID,
            style=wx.TR_HIDE_ROOT | wx.TR_HAS_BUTTONS | wx.TR_NO_LINES
            | wx.TR_DEFAULT_STYLE | wx.SUNKEN_BORDER | wx.TR_MULTIPLE)
        self.treeCtrl_Doz = wx.TreeCtrl(
            self.notebook_1_pane_2,
            TREE_CTRL_DOZ_ID,
            style=wx.TR_HIDE_ROOT | wx.TR_HAS_BUTTONS | wx.TR_NO_LINES
            | wx.TR_DEFAULT_STYLE | wx.SUNKEN_BORDER | wx.TR_MULTIPLE)

        self.__doLayout()
        self.__doFrameBindings()
        self.__doMenuBindings()

        self.menuItem_AlleSemUndDoz = self.menuBar.FindItemById(
            ITEM_BATCH_EXPORT_ID)
        self.menuItem_AlleSemUndDoz.Enable(False)

        self.space = "      "

    def __doLayout(self):
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4.Add(self.button_Load, 0, 0, 0)
        sizer_4.Add(self.button_Export, 0, 0, 0)
        sizer_5.Add(self.infoString, 0,
                    wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 0)
        self.panel_1.SetSizer(sizer_5)
        sizer_4.Add(self.panel_1, 1, wx.EXPAND | wx.ALIGN_RIGHT, 0)
        sizer_1.Add(sizer_4, 0, 0, 0)
        sizer_2.Add(self.treeCtrl_Stud, 1, wx.EXPAND, 0)
        self.notebook_1_pane_1.SetSizer(sizer_2)
        sizer_3.Add(self.treeCtrl_Doz, 1, wx.EXPAND, 0)
        self.notebook_1_pane_2.SetSizer(sizer_3)
        self.notebook_1.AddPage(self.notebook_1_pane_1, "Studentensicht")
        self.notebook_1.AddPage(self.notebook_1_pane_2, "Dozentensicht")
        sizer_1.Add(self.notebook_1, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()

    def __doFrameBindings(self):
        self.button_Load.Bind(wx.EVT_BUTTON, self.onButton_Load)
        self.button_Export.Bind(wx.EVT_BUTTON, self.onButton_Export)
        self.button_Export.Disable()
        self.treeCtrl_Stud.Bind(wx.EVT_TREE_ITEM_ACTIVATED,
                                self.onDoubleClick_Stud)
        self.treeCtrl_Doz.Bind(wx.EVT_TREE_ITEM_ACTIVATED,
                               self.onDoubleClick_Doz)

    def __doMenuBindings(self):

        self.Bind(wx.EVT_MENU,
                  self.onMenuItem_BatchStudUndDoz,
                  id=ITEM_BATCH_EXPORT_ID)

        self.Bind(wx.EVT_MENU, self.onMenuItem_EuI, id=ITEM_EUI_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_EuI_load, id=ITEM_EUI_LOAD_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_Inf, id=ITEM_INF_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_Inf_load, id=ITEM_INF_LOAD_ID)
        self.Bind(wx.EVT_MENU,
                  self.onMenuItem_GoogleCalendar,
                  id=ITEM_GOOGLE_CALENDAR_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_rfc5545, id=ITEM_RFC5545_ID)

        self.Bind(wx.EVT_MENU, self.onMenuItem_Anleitung, id=ITEM_HELP_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_GPL, id=ITEM_GPL_ID)
        self.Bind(wx.EVT_MENU, self.onMenuItem_About, id=ITEM_ABOUT_ID)

    def onButton_Load(self, event):
        dlg = wx.FileDialog(self, "txt-Version des Semesterplans auswählen")
        dlg.SetWildcard("nur Textdateien (*.txt)|*.txt|alle Dateien|*")

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.ctrl = Controller(inFileName=path, outFileName=None)
            self.infoString.SetLabel(self.space + "HAW-Kalender: " +
                                     self.ctrl.getInfoString())

            self.fillTrees()

        dlg.Destroy()

        self.updateExportButton()
        self.menuItem_AlleSemUndDoz.Enable()

    def fillTrees(self):
        def fillTree(treeCtrl):
            font = wx.Font(12, wx.MODERN, wx.NORMAL, wx.NORMAL, False,
                           u'Courier New')
            treeCtrl.SetFont(font)

            groups = sorted(self.ctrl.getKeys())
            treeCtrl.DeleteAllItems()
            rootName = "root"
            rootName_unicode = rootName.decode("utf-8")
            root = treeCtrl.AddRoot(rootName_unicode)
            for key in groups:
                key_unicode = key.decode("utf-8")
                parent = treeCtrl.AppendItem(root, key_unicode)
                veranstaltungen = sorted(self.ctrl.getVeranstaltungen(key))

                maxLen = len(
                    reduce(lambda x, y: max(x, y, key=len), veranstaltungen))
                formatter = "{0:<" + str(maxLen + 3) + "}"

                for veranstaltung in veranstaltungen:
                    leftAlignedVeranstaltung = formatter.format(veranstaltung)
                    #FIXME: dirty hack (a 'Ü' is represented in utf-8 by 2 byte)
                    if 'Ü' in leftAlignedVeranstaltung:
                        leftAlignedVeranstaltung += " "
                    s = leftAlignedVeranstaltung + self.ctrl.tryGetFullName(
                        veranstaltung)
                    s_unicode = s.decode("utf-8")
                    treeCtrl.AppendItem(parent, s_unicode)

        self.ctrl.tupleKeyIndex = DOZENT
        fillTree(self.treeCtrl_Doz)

        self.ctrl.tupleKeyIndex = self.ctrl.optimalGruppenKeyIndex()
        fillTree(self.treeCtrl_Stud)

    def onButton_Export(self, event):
        style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT
        dlg = wx.FileDialog(self,
                            message="iCalendar (.ics) speichern unter",
                            style=style)
        dlg.SetWildcard("iCalendar-Dateien (*.ics)|*.ics")

        if dlg.ShowModal() == wx.ID_OK:

            path = dlg.GetPath()
            if not path.endswith(".ics"):
                path = path + ".ics"

            self.ctrl.setOutFileName(path)
            self.ctrl.writeIcalendar()

        dlg.Destroy()

    def onDoubleClick_Stud(self, wxTreeEvent):
        self.ctrl.tupleKeyIndex = self.ctrl.optimalGruppenKeyIndex()
        self.onDoubleClick(wxTreeEvent, self.treeCtrl_Stud)

    def onDoubleClick_Doz(self, wxTreeEvent):
        self.ctrl.tupleKeyIndex = DOZENT
        self.onDoubleClick(wxTreeEvent, self.treeCtrl_Doz)

    def onDoubleClick(self, wxTreeEvent, treeCtrl):
        itemId = wxTreeEvent.GetItem()

        text_unicode = treeCtrl.GetItemText(itemId)
        text_utf8 = text_unicode.encode("utf-8")

        isVeranstaltung = not treeCtrl.ItemHasChildren(itemId)

        if not isVeranstaltung:
            key = text_utf8
            veranstaltungen = self.ctrl.getVeranstaltungen(key)
            if self.groupFullSelected(key):
                self.ctrl.unselectVeranstaltungen(veranstaltungen)
            else:
                self.ctrl.selectVeranstaltungen(veranstaltungen)
        else:
            veranstaltung = text_utf8.split("   ")[0]  #FIXME: dirty
            if veranstaltung in self.ctrl.selectedVeranstaltungen:
                self.ctrl.selectedVeranstaltungen.remove(veranstaltung)
            else:
                self.ctrl.selectedVeranstaltungen.add(veranstaltung)

        self.updateTrees()
        self.updateExportButton()

    def updateTrees(self):
        def updateTree(treeCtrl):
            for keyItemId in iterChildren(treeCtrl, treeCtrl.GetRootItem()):

                allSelected = True
                for veranstItemId in iterChildren(treeCtrl, keyItemId):

                    text_unicode = treeCtrl.GetItemText(veranstItemId)
                    veranstaltung = text_unicode.encode("utf-8").split("   ")[
                        0]  #FIXME: dirty

                    if not veranstaltung in self.ctrl.selectedVeranstaltungen:
                        treeCtrl.SetItemBold(veranstItemId, False)
                        allSelected = False
                    else:
                        treeCtrl.SetItemBold(veranstItemId)

                treeCtrl.SetItemBold(keyItemId, allSelected)

            treeCtrl.Refresh()

        updateTree(self.treeCtrl_Stud)
        updateTree(self.treeCtrl_Doz)

    def updateExportButton(self):
        if len(self.ctrl.selectedVeranstaltungen) > 0:
            self.button_Export.Enable()
        else:
            self.button_Export.Disable()

    def groupFullSelected(self, key):
        return (self.ctrl.selectedVeranstaltungen
                & set(self.ctrl.getVeranstaltungen(key)) == set(
                    self.ctrl.getVeranstaltungen(key)))

    def onMenuItem_BatchStudUndDoz(self, event):

        dlg = wx.DirDialog(self, "Verzeichnis für Batch-Export auswählen")

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            dlg.Destroy()

            batchCtrl = copy.deepcopy(self.ctrl)

            dlg = RunningBatchExportDialog(parent=self,
                                           text="Batch-Export gestartet:\n\n",
                                           title="Batch-Export",
                                           ctrl=batchCtrl,
                                           path=path)
            dlg.ShowModal()
            dlg.Destroy()

    def onMenuItem_EuI(self, event):
        webbrowser.open(STUNDENPLAN_SITE_EuI, autoraise=True)

    def onMenuItem_EuI_load(self, event):
        try:
            sys.stdin = urllib.urlopen(STUNDENPLAN_URL_EuI)
            self.ctrl = Controller(inFileName=None, outFileName=None)
            self.infoString.SetLabel(self.space + "HAW-Kalender: " +
                                     self.ctrl.getInfoString())
            self.fillTrees()

            self.updateExportButton()

            self.menuItem_AlleSemUndDoz.Enable()

        except IOError as e:
            print "Could not open EuI-url: " + str(e)

    def onMenuItem_Inf(self, event):
        webbrowser.open(STUNDENPLAN_SITE_Inf, autoraise=True)

    def onMenuItem_Inf_load(self, event):
        try:
            sys.stdin = urllib.urlopen(STUNDENPLAN_URL_Inf)
            self.ctrl = Controller(inFileName=None, outFileName=None)
            self.infoString.SetLabel(self.space + "HAW-Kalender: " +
                                     self.ctrl.getInfoString())
            self.fillTrees()

            self.updateExportButton()

            self.menuItem_AlleSemUndDoz.Enable()

        except IOError as e:
            print "Couldn't open Inf-url: " + str(e)

    def onMenuItem_GoogleCalendar(self, event):
        webbrowser.open("http://www.google.com/calendar", autoraise=True)

    def onMenuItem_rfc5545(self, event):
        webbrowser.open("http://tools.ietf.org/html/rfc5545/", autoraise=True)

    def onMenuItem_Anleitung(self, event):

        text_unicode = texts.anleitung.decode("utf-8")

        dlg = ScrollableDialog(None, text_unicode, title="Anleitung")
        dlg.ShowModal()
        dlg.Destroy()

    def onMenuItem_GPL(self, event):

        text = texts.gpl
        text = " " + text.replace("\n", "\n ")
        text_unicode = text.decode("utf-8")

        dlg = ScrollableDialog(self, text_unicode, title="GPL")
        dlg.ShowModal()
        dlg.Destroy()

    def onMenuItem_About(self, event):

        text = texts.version + "\n\n" + texts.homepage + "\n\n" + texts.about
        text_unicode = text.decode("utf-8")

        dlg = wx.MessageDialog(self,
                               text_unicode,
                               caption="About",
                               style=wx.OK)
        dlg.ShowModal()
        dlg.Destroy()