Beispiel #1
0
def adminProjectsPost(handler, p_name):
	handler.title('Project Management')
	requirePriv(handler, 'Admin')

	if Project.load(name = p_name):
		ErrorBox.die('Add Project', "There is already a project named <b>%s</b>" % stripTags(p_name))

	project = Project(p_name)
	project.save()
	delay(handler, SuccessBox("Added project <b>%s</b>" % stripTags(p_name), close = True))
	Event.newProject(handler, project)
	redirect('/')
Beispiel #2
0
class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        
        self.menubar = wx.MenuBar()
        self.menu_file = wx.Menu()
        self.menu_new = wx.MenuItem(self.menu_file, 101, "&New", "", wx.ITEM_NORMAL)
        self.menu_file.AppendItem(self.menu_new)
        self.menu_open = wx.MenuItem(self.menu_file, 102, "&Open", "", wx.ITEM_NORMAL)
        self.menu_file.AppendItem(self.menu_open)
        self.menu_save = wx.MenuItem(self.menu_file, 103, "&Save", "", wx.ITEM_NORMAL)
        self.menu_file.AppendItem(self.menu_save)
        self.menu_saveas = wx.MenuItem(self.menu_file, 104, "Save &As", "", wx.ITEM_NORMAL)
        self.menu_file.AppendItem(self.menu_saveas)
        self.menu_file.AppendSeparator()
        self.menu_close = wx.MenuItem(self.menu_file, 105, "&Close", "", wx.ITEM_NORMAL)
        self.menu_file.AppendItem(self.menu_close)
        self.menubar.Append(self.menu_file, "&File")
        self.menu_about = wx.Menu()
        self.menu_about_pysaved = wx.MenuItem(self.menu_about, 201, "&About PySaved", "", wx.ITEM_NORMAL)
        self.menu_about.AppendItem(self.menu_about_pysaved)
        self.menubar.Append(self.menu_about, "&About")
        self.SetMenuBar(self.menubar)
        
        self.nb = wx.Notebook(self, wx.ID_ANY, style=0)
        self.nb_panel_1 = wx.Panel(self.nb, wx.ID_ANY)
        self.label_name = wx.StaticText(self.nb_panel_1, wx.ID_ANY, "Name:")
        self.input_name = wx.TextCtrl(self.nb_panel_1, wx.ID_ANY, "")
        self.label_icon = wx.StaticText(self.nb_panel_1, wx.ID_ANY, "Icon (Windows only):")
        self.input_icon = wx.TextCtrl(self.nb_panel_1, wx.ID_ANY, "")
        self.button_search_icon = wx.BitmapButton(self.nb_panel_1, wx.ID_ANY, statics.search(), style=wx.NO_BORDER)
        self.label_execfile = wx.StaticText(self.nb_panel_1, wx.ID_ANY, "Executable file:")
        self.input_execfile = wx.TextCtrl(self.nb_panel_1, wx.ID_ANY, "")
        self.button_search_execfile = wx.BitmapButton(self.nb_panel_1, wx.ID_ANY, statics.search(), style=wx.NO_BORDER)
        self.radiobox_console = wx.RadioBox(self.nb_panel_1, wx.ID_ANY, "Console (Windows only)", choices=["show", "hide"], majorDimension=0, style=wx.RA_SPECIFY_COLS)
        self.sl1 = wx.StaticLine(self.nb_panel_1, wx.ID_ANY)
        self.label_pathstosearchin = wx.StaticText(self.nb_panel_1, wx.ID_ANY, "Paths to search in:")
        self.list_pathstosearchin = wx.ListBox(self.nb_panel_1, wx.ID_ANY, choices=[])
        self.button_pathstosearchin_add = wx.BitmapButton(self.nb_panel_1, wx.ID_ANY, statics.add(), style=wx.NO_BORDER)
        self.button_pathstosearchin_edit = wx.BitmapButton(self.nb_panel_1, wx.ID_ANY, statics.edit(), style=wx.NO_BORDER)
        self.button_pathstosearchin_del = wx.BitmapButton(self.nb_panel_1, wx.ID_ANY, statics.dele(), style=wx.NO_BORDER)
        self.label_hiddenmodules = wx.StaticText(self.nb_panel_1, wx.ID_ANY, "Hidden modules:")
        self.list_hiddenmodules = wx.CheckListBox(self.nb_panel_1, wx.ID_ANY, choices=[])
        self.nb_pane_2 = wx.Panel(self.nb, wx.ID_ANY)
        self.label_outpath = wx.StaticText(self.nb_pane_2, wx.ID_ANY, "Output path:")
        self.input_outpath = wx.TextCtrl(self.nb_pane_2, wx.ID_ANY, "")
        self.search_outpath = wx.BitmapButton(self.nb_pane_2, wx.ID_ANY, statics.search(), style=wx.NO_BORDER)
        self.label_temppath = wx.StaticText(self.nb_pane_2, wx.ID_ANY, "Temporary path:")
        self.input_temppath = wx.TextCtrl(self.nb_pane_2, wx.ID_ANY, "")
        self.search_temppath = wx.BitmapButton(self.nb_pane_2, wx.ID_ANY, statics.search(), style=wx.NO_BORDER)
        self.sl2 = wx.StaticLine(self.nb_pane_2, wx.ID_ANY)
        self.radiobox_saveas = wx.RadioBox(self.nb_pane_2, wx.ID_ANY, "Save as", choices=["multiple files in one folder", "one file"], majorDimension=0, style=wx.RA_SPECIFY_COLS)
        self.checkbox_debug = wx.CheckBox(self.nb_pane_2, wx.ID_ANY, "Debug-mode")
        self.checkbox_unicode = wx.CheckBox(self.nb_pane_2, wx.ID_ANY, "Support unicode")
        self.sl3 = wx.StaticLine(self.nb_pane_2, wx.ID_ANY)
        self.bitmap_start = wx.BitmapButton(self.nb_pane_2, wx.ID_ANY, statics.start(), style=wx.NO_BORDER)
        self.sl4 = wx.StaticLine(self.nb_pane_2, wx.ID_ANY)
        self.label_log = wx.StaticText(self.nb_pane_2, wx.ID_ANY, "Log:")
        self.list_log = wx.ListBox(self.nb_pane_2, wx.ID_ANY, choices=[])

        self.Bind(wx.EVT_MENU, self.new, self.menu_new)
        self.Bind(wx.EVT_MENU, self.open, self.menu_open)
        self.Bind(wx.EVT_MENU, self.save, self.menu_save)
        self.Bind(wx.EVT_MENU, self.saveas, self.menu_saveas)
        self.Bind(wx.EVT_MENU, self.exit, self.menu_close)
        self.Bind(wx.EVT_MENU, self.about, self.menu_about_pysaved)
        self.Bind(wx.EVT_BUTTON, self.search_icon, self.button_search_icon)
        self.Bind(wx.EVT_BUTTON, self.search_execfile, self.button_search_execfile)
        self.Bind(wx.EVT_BUTTON, self.addPath, self.button_pathstosearchin_add)
        self.Bind(wx.EVT_BUTTON, self.editPath, self.button_pathstosearchin_edit)
        self.Bind(wx.EVT_BUTTON, self.delPath, self.button_pathstosearchin_del)
        self.Bind(wx.EVT_BUTTON, self.event_search_outpath, self.search_outpath)
        self.Bind(wx.EVT_BUTTON, self.event_search_temppath, self.search_temppath)
        self.Bind(wx.EVT_BUTTON, self.start, self.bitmap_start)
        self.Bind(wx.EVT_CLOSE, self.exit)

        self.__set_properties()
        self.__do_layout()

        self.project = Project()
        self.project.loadAllhiddenmodules(self)
        self.project.initialFrame(self)
        self.path = None
        self.progress= False
        
    def __set_properties(self):
        self.SetTitle("PySaved")
        self.SetMinSize(wx.Size(780, 820))
        self.label_name.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
        self.input_name.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        self.label_icon.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
        self.input_icon.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        self.button_search_icon.SetSize(self.button_search_icon.GetBestSize())
        self.label_execfile.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
        self.input_execfile.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        self.button_search_execfile.SetSize(self.button_search_execfile.GetBestSize())
        self.radiobox_console.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        try: self.radiobox_console.SetSelection(0)
        except: pass
        self.label_pathstosearchin.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
        self.list_pathstosearchin.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        try: self.list_pathstosearchin.SetSelection(0)
        except: pass
        self.button_pathstosearchin_add.SetSize(self.button_pathstosearchin_add.GetBestSize())
        self.button_pathstosearchin_edit.SetSize(self.button_pathstosearchin_edit.GetBestSize())
        self.button_pathstosearchin_del.SetSize(self.button_pathstosearchin_del.GetBestSize())
        self.label_hiddenmodules.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
        try: self.list_hiddenmodules.SetSelection(0)
        except: pass
        self.label_outpath.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
        self.input_outpath.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        self.search_outpath.SetSize(self.search_outpath.GetBestSize())
        self.label_temppath.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
        self.input_temppath.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        self.search_temppath.SetSize(self.search_temppath.GetBestSize())
        self.radiobox_saveas.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        try: self.radiobox_saveas.SetSelection(0)
        except: pass
        self.checkbox_debug.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        self.checkbox_unicode.SetValue(1)
        self.bitmap_start.SetSize(self.bitmap_start.GetBestSize())
        self.label_log.SetFont(wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
        self.list_log.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
        try: self.list_log.SetSelection(0)
        except: pass

    def __do_layout(self):
        main_sizer = wx.FlexGridSizer(3, 3, 0, 0)
        grid_sizer_2 = wx.FlexGridSizer(9, 1, 10, 0)
        grid_sizer_4 = wx.FlexGridSizer(1, 2, 0, 10)
        grid_sizer_3 = wx.FlexGridSizer(2, 3, 15, 15)
        grid_sizer_5 = wx.FlexGridSizer(4, 1, 15, 0)
        grid_sizer_7 = wx.FlexGridSizer(2, 3, 15, 15)
        grid_sizer_8 = wx.FlexGridSizer(3, 1, 5, 0)
        grid_sizer_6 = wx.FlexGridSizer(3, 3, 10, 10)
        main_sizer.Add((20, 20), 0, 0, 0)
        main_sizer.Add((20, 20), 0, 0, 0)
        main_sizer.Add((20, 20), 0, 0, 0)
        main_sizer.Add((20, 20), 0, 0, 0)
        grid_sizer_6.Add(self.label_name, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_6.Add(self.input_name, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_6.Add((10, 30), 0, 0, 0)
        grid_sizer_6.Add(self.label_icon, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_6.Add(self.input_icon, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_6.Add(self.button_search_icon, 0, 0, 0)
        grid_sizer_6.Add(self.label_execfile, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_6.Add(self.input_execfile, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_6.Add(self.button_search_execfile, 0, 0, 0)
        grid_sizer_6.AddGrowableCol(1)
        grid_sizer_5.Add(grid_sizer_6, 1, wx.EXPAND, 0)
        grid_sizer_5.Add(self.radiobox_console, 0, 0, 0)
        grid_sizer_5.Add(self.sl1, 0, wx.EXPAND, 0)
        grid_sizer_7.Add(self.label_pathstosearchin, 0, 0, 0)
        grid_sizer_7.Add(self.list_pathstosearchin, 0, wx.EXPAND, 0)
        grid_sizer_8.Add(self.button_pathstosearchin_add, 0, 0, 0)
        grid_sizer_8.Add(self.button_pathstosearchin_edit, 0, 0, 0)
        grid_sizer_8.Add(self.button_pathstosearchin_del, 0, 0, 0)
        grid_sizer_7.Add(grid_sizer_8, 1, wx.EXPAND, 0)
        grid_sizer_7.Add(self.label_hiddenmodules, 0, 0, 0)
        grid_sizer_7.Add(self.list_hiddenmodules, 0, wx.EXPAND, 0)
        grid_sizer_7.Add((20, 20), 0, 0, 0)
        grid_sizer_7.AddGrowableRow(0)
        grid_sizer_7.AddGrowableRow(1)
        grid_sizer_7.AddGrowableCol(1)
        grid_sizer_5.Add(grid_sizer_7, 1, wx.EXPAND, 0)
        self.nb_panel_1.SetSizer(grid_sizer_5)
        grid_sizer_5.AddGrowableRow(3)
        grid_sizer_5.AddGrowableCol(0)
        grid_sizer_3.Add(self.label_outpath, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_3.Add(self.input_outpath, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_3.Add(self.search_outpath, 0, 0, 0)
        grid_sizer_3.Add(self.label_temppath, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_3.Add(self.input_temppath, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_3.Add(self.search_temppath, 0, 0, 0)
        grid_sizer_3.AddGrowableCol(1)
        grid_sizer_2.Add(grid_sizer_3, 1, wx.EXPAND, 0)
        grid_sizer_2.Add(self.sl2, 0, wx.EXPAND, 0)
        grid_sizer_2.Add(self.radiobox_saveas, 0, 0, 0)
        grid_sizer_4.Add(self.checkbox_debug, 0, 0, 0)
        grid_sizer_4.Add(self.checkbox_unicode, 0, 0, 0)
        grid_sizer_2.Add(grid_sizer_4, 1, wx.EXPAND, 0)
        grid_sizer_2.Add(self.sl3, 0, wx.EXPAND, 0)
        grid_sizer_2.Add(self.bitmap_start, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
        grid_sizer_2.Add(self.sl4, 0, wx.EXPAND, 0)
        grid_sizer_2.Add(self.label_log, 0, 0, 0)
        grid_sizer_2.Add(self.list_log, 0, wx.EXPAND, 0)
        self.nb_pane_2.SetSizer(grid_sizer_2)
        grid_sizer_2.AddGrowableRow(8)
        grid_sizer_2.AddGrowableCol(0)
        self.nb.AddPage(self.nb_panel_1, "Project")
        self.nb.AddPage(self.nb_pane_2, "Build")
        main_sizer.Add(self.nb, 1, wx.EXPAND, 0)
        main_sizer.Add((20, 20), 0, 0, 0)
        main_sizer.Add((20, 20), 0, 0, 0)
        main_sizer.Add((20, 20), 0, 0, 0)
        main_sizer.Add((20, 20), 0, 0, 0)
        self.SetSizer(main_sizer)
        main_sizer.Fit(self)
        main_sizer.AddGrowableRow(1)
        main_sizer.AddGrowableCol(1)
        self.Layout()

    def askForSavingIfNeed(self):
        if (self.path == None or self.project.needSave(self)) and not self.project.isEmpty(self):
            res = wx.MessageDialog(self, "Do you want to save this project?", "Save?", wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.YES_DEFAULT).ShowModal()
            
            if res == wx.ID_CANCEL:
                return False
            elif res == wx.ID_YES:
                self.save(None)
        return True
    
    def new(self, event):
        if self.askForSavingIfNeed():
            self.project = Project()
            self.project.loadAllhiddenmodules(self)
            self.project.initialFrame(self)
            self.path = None

    def open(self, event=None, path=None):
        if self.askForSavingIfNeed():
            if path == None:
                dia = wx.FileDialog(self, "Select a file to open", wildcard="PySaved-files (*.pysa)|*.pysa", style=wx.FD_OPEN)
                if dia.ShowModal() == wx.ID_OK:
                    path = dia.GetPath()
                else: return

            try:
                print(u"Loading project from: '{0}'".format(path))                
                p = Project()
                p.load(self, path)
                self.project = p
                self.project.loadAllhiddenmodules(self)
                self.path = path
            except:
                wx.MessageDialog(self, u"Cannot open file: '{0}'".format(path), "Cannot open file", wx.ICON_ERROR).ShowModal()
                raise

    def save(self, event):
        if self.path == None:
            self.saveas(None)
        else:
            try:
                print(u"Saving project at: '{}'".format(self.path))
                self.project.save(self, self.path)
            except:
                wx.MessageDialog(self, u"Cannot save file: '{0}'".format(self.path), "Cannot save file", wx.ICON_ERROR).ShowModal()
                self.path = None

    def saveas(self, event):
        dia = wx.FileDialog(self, "Select a file to save", wildcard="PySaved-files (*.pysa)|*.pysa", style=wx.FD_SAVE)
        if dia.ShowModal() == wx.ID_OK:
            self.path = dia.GetPath()
            if ".pysa" not in self.path:
                self.path += ".pysa"
            self.save(None)

    def exit(self, event):
        if self.askForSavingIfNeed() and not self.progress:
            print("\nQuit PySaved...")
            sys.exit(0)

    def search_icon(self, event):
        dia = wx.FileDialog(self, "Select a file to open", wildcard="Icon-files (*.ico)|*.ico", style=wx.FD_OPEN)
        if dia.ShowModal() == wx.ID_OK:
            self.input_icon.SetValue(dia.GetPath())

    def search_execfile(self, event):
        dia = wx.FileDialog(self, "Select a file to open", wildcard="Python-files (*.py)|*.py", style=wx.FD_OPEN)
        if dia.ShowModal() == wx.ID_OK:
            self.input_execfile.SetValue(dia.GetPath())

    def addPath(self, event):
        dia = wx.DirDialog(self, "Select a dir")
        if dia.ShowModal() == wx.ID_OK:
            if dia.GetPath() not in self.project.pathstosearchin:
                self.project.pathstosearchin.append(dia.GetPath())
                self.project.loadAllhiddenmodules(self)
            
    def editPath(self, event):
        sel = self.list_pathstosearchin.GetSelection()
        strSel = self.list_pathstosearchin.GetStringSelection()
        if sel == -1: return
        
        while True:
            dia = wx.TextEntryDialog(self, u"Enter a new path for '{}'".format(strSel), "Edit Path", strSel)
            if dia.ShowModal() == wx.ID_OK:
                if dia.GetValue().strip() == "" or not os.path.exists(dia.GetValue()):
                    wx.MessageDialog(self, "Unknown path!", "", wx.ICON_ERROR).ShowModal()
                else:
                    self.project.pathstosearchin[sel] = dia.GetValue()
                    self.project.loadAllhiddenmodules(self)
                    break

    def delPath(self, event):
        sel = self.list_pathstosearchin.GetSelection()
        if sel == -1: return
        del(self.project.pathstosearchin[sel])
        self.project.loadAllhiddenmodules(self)

    def event_search_outpath(self, event):
        dia = wx.DirDialog(self, "Select a dir to save in")
        if dia.ShowModal() == wx.ID_OK:
            self.input_outpath.SetValue(dia.GetPath())

    def event_search_temppath(self, event):
        dia = wx.DirDialog(self, "Select a dir to save in")
        if dia.ShowModal() == wx.ID_OK:
            self.input_outpath.SetValue(dia.GetPath())

    def start(self, event):
        self.project.loadFromFrame(self)
        c = builder.Connector(self.project)
        thread.start_new(self.loop, (c,))
        thread.start_new(builder.build, (c,))
        thread.start_new(builder.log, (c,))
    
    def loop(self, c):
        def success():
            wx.MessageDialog(self, "Building package successful!", "Successful!", wx.ICON_INFORMATION).ShowModal()
        def error(fm):
            wx.MessageDialog(self, u"Error while building package:\n\n{}".format(fm), "Error!", wx.ICON_ERROR).ShowModal()
        def log(l):
            self.list_log.SetItems(l)
            self.list_log.Select(len(l)-1)
        
        self.progress = True
        wx.CallAfter(self.Disable)
        while True:
            time.sleep(0.1)
            
            wx.CallAfter(log, c.log)
                
            if c.finished:
                wx.CallAfter(success)
                break
            elif c.error:
                wx.CallAfter(error, c.errormsg)
                break
        
        wx.CallAfter(self.Enable, True)
        self.progress = False
    
    def about(self, event):
        info = wx.AboutDialogInfo()
        
        info.SetName("PySaved")
        info.SetVersion("0.1")
        info.SetCopyright("(c) 2015 by Arne Hannappel")
        info.AddArtist("Adrian Gisder")
        info.SetWebSite("http://www.arnehannappel.de/index.php/programme/pysaved")
        info.SetDescription("PySaved is a simple GUI for PyInstaller, a program that converts Python (2.6-2.7) programs into stand-alone executables.")
        info.SetLicence(statics.gplv2)
        
        wx.AboutBox(info)
class StoryDNA:
    def __init__(self):
        self.project = None
        self.secureQuit = True  # attribute to know if script have to ask to save current project before quitting

        # create the app main window
        self.window = Tk(className="StoryDNA")
        self.window.option_add("*Font", "arial 12")
        self.window.geometry(
            str(self.window.winfo_screenwidth()) + "x" + str(self.window.winfo_screenheight()) + "+0+0"
        )

        # activate general shortcut for menu and mouse scrolling
        self.window.bind("<Control-KeyPress>", self.shortcut)
        self.window.bind_all("<Button-5>", mouseScroll)
        self.window.bind_all("<Button-4>", mouseScroll)

        # create the menu of the software
        self.menubar = Menu(self.window)
        menu = Menu(self.menubar, tearoff=0)

        # submenu of File menu
        menu.add_command(label="New", command=self.new)
        menu.add_command(label="Open", command=self.open)
        menu.add_command(label="Save", command=self.save, state=DISABLED)
        menu.add_command(label="Save As", command=self.saveAs, state=DISABLED)
        menu.add_command(label="Quit", command=self.quit)
        self.window.protocol("WM_DELETE_WINDOW", self.quit)

        self.menubar.add_cascade(label="File", menu=menu)

        # Settings menu and submenu
        menu = Menu(self.menubar, tearoff=0)
        menu.add_command(label="Archetypes", command=lambda win=self.window: Character.setArchetypesList(win))
        self.menubar.add_cascade(label="Settings", menu=menu)

        self.window.config(menu=self.menubar)

        # create content of starting window :
        #    button to open a project or create a new one
        fr = Frame(self.window, pady=300)
        fr.pack()

        button = Button(fr, text="NEW PROJECT", command=self.new, pady=5, justify=CENTER)
        button.pack(pady=5)

        button = Button(fr, text="OPEN A PROJECT", command=self.open, pady=5, justify=CENTER)
        button.pack(pady=5)

        # warning message
        label = Label(
            fr,
            text="This soft is still in development and is not ready to use!",
            foreground="#ff0000",
            pady=50,
            font=("Arial", 50),
            wraplength=800,
            justify=LEFT,
        )
        label.pack()

        # treat the app argument
        argv = sys.argv
        while len(argv) > 1:
            arg = argv.pop()
            if arg == "--no-secure-quit":
                # disabled the safe quitting mode
                self.secureQuit = False
            else:
                path = os.path.abspath(arg)

                # check the path given and open it as a project
                if not os.access(path, os.F_OK):
                    showerror("Load error", "«" + path + "» didn't exist or is not a file!")
                elif not (os.access(path, os.R_OK) and os.access(path, os.W_OK)):
                    showerror("Load error", "you don't have permission to read or write in «" + path + "» file!")
                elif path[-5:] != ".sdna" or not tarfile.is_tarfile(path):
                    showerror("Load error", "«" + path + "» don't seemed to be a valid Story DNA file!")
                else:
                    fr.destroy()  # erase content of starting window
                    self.open(path=path)  # open the project

        self.window.mainloop()

        # erase the temporary directory before quitting
        if self.project is not None:
            self.project.__del__()

    def shortcut(self, event):
        """call action corresponding to a shortcut"""
        if event.keysym == "q":
            self.quit()
        elif event.keysym == "Q":
            self.quit(True)  # quit app directly without saving
        elif event.keysym == "n":
            self.new()
        elif event.keysym == "o":
            self.open()
        elif event.keysym == "s" and self.project is not None:
            focus = self.window.focus_displayof()
            focus.event_generate("<FocusOut>")
            self.save()
            focus.focus()
        elif event.keysym == "S" and self.project is not None:
            focus = self.window.focus_displayof()
            focus.event_generate("<FocusOut>")
            self.saveAs()
            focus.focus()

    def quit(self, forced=False):
        """securely quit application"""
        if self.secureQuit and self.project is not None and not forced:
            if askyesno("Secure quit", "Do you want to save before to quit?"):
                self.save()
        self.window.quit()

    def new(self):
        """create a new Story DNA Project"""
        # ask to save current project first
        if self.project is not None:
            if askyesno("Save before new project", "Do you want to save current project before to create a new one?"):
                self.save()

                # ask a name for the new project
        name = textRequest(
            "New Project", "What's the name of your new Story DNA project?", "Name :", "New Project"
        ).wait()

        if name is not None:
            if self.project is not None:
                self.project.__del__()

                # load the new project and display it
            self.project = Project(name)
            self.window.wm_title(name)
            self.menubar.winfo_children()[0].entryconfigure(2, state="active")  # active Save
            self.menubar.winfo_children()[0].entryconfigure(3, state="active")  # active Save As
            self.project.show(self.window)

    def open(self, path=None):
        """a method to save the project"""
        # ask to save current project first
        if self.project is not None:
            if askyesno("Save current project", "Do you want to save the current project before opening another one?"):
                self.save()

                # ask a path if path argument is None
        if path is None:
            while True:
                path = askopenfilename(
                    title="Open a project?",
                    initialdir="~/Documents/",
                    defaultextension=".sdna",
                    filetypes=[("StoryDNA files", ".sdna")],
                )

                if path == () or path == "":  # check a path is given
                    return False
                elif path[-5:] != ".sdna":  # check if it's a Story DNA file
                    showerror(
                        "Wrong path", "«" + path + "» is not a Story DNA file. The file name must end by «.sdna»!"
                    )
                    continue
                elif not (os.access(path, os.W_OK) and os.access(path, os.R_OK)):
                    # check file permission
                    showerror("Wrong path", "You don't have the permission to read or write in «" + path + "» !")
                    continue
                elif not tarfile.is_tarfile(path):  # check if the file is a valid tar file
                    showerror("Wrong path", "«" + path + "» don't seemed to be a valid Story DNA file!")
                    continue
                else:
                    break

                    # open and display the required project
        if self.project is not None:
            shutil.rmtree(self.project.temp)
        self.project = Project(path=path)
        self.window.wm_title(self.project.name)
        self.menubar.winfo_children()[0].entryconfigure(2, state="active")  # active Save
        self.menubar.winfo_children()[0].entryconfigure(3, state="active")  # active Save As
        self.project.show(self.window)

    def save(self):
        """a method to save the project"""
        if self.project.fullpath is None:
            # if the project have never been saved
            return self.saveAs()
        else:
            self.project.save()

    def saveAs(self):
        """a method to save the project"""
        while True:
            # ask a path to save the project
            fullpath = asksaveasfilename(
                title="Where do you want to save «" + self.project.name + "» project?",
                initialdir="~/Documents/",
                defaultextension=".sdna",
                filetypes=[("StoryDNA files", ".sdna")],
                initialfile=self.project.name + ".sdna",
            )
            if fullpath == () or fullpath == "":  # if saving canceled
                return False
            else:
                # deducte new project path and name from the fullpath given
                if fullpath[-5:] != ".sdna":
                    fullpath += ".sdna"
                name = fullpath[fullpath.rfind("/") + 1 : fullpath.rfind(".")]
                path = fullpath[0 : fullpath.rfind("/")]

                if os.access(path, os.W_OK):  # check writting permission
                    # apply the new path and name to the project
                    self.project.name = name
                    self.window.wm_title(name)
                    self.project.path = path
                    self.project.fullpath = fullpath

                    # save the project
                    return self.save()
                else:  # don't have permission to write target path
                    showwarning("Permission error", "You don't have the permission to write in this directory!")