Ejemplo n.º 1
0
class WahCade:
    """Common functions for Wah!Cade"""

    def __init__(self):
        """initialise common wahcade class"""
        #set default icon for windows
        gtk.window_set_default_icon_from_file(
            os.path.join(APP_PATH, 'pixmaps', 'wahcade.png'))
        ### LOGFILE
        if os.path.exists(CONFIG_DIR):
            self.log_filename = os.path.join(CONFIG_DIR, 'wahcade.log')
            try:
                f = open(self.log_filename, 'w')
                self.log_msg("//======================= NEW LOG RUN =======================//")
                f.close
            except:
                print "ERROR opening LOG FILE, %s, check for orphaned processes" % self.log_filename

    def hide_mouse_cursor(self, win):
        """hide mouse cursor"""
        gtk_col = gtk.gdk.Color()
        pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
        invisible_cursor = gtk.gdk.Cursor(
            pixmap, pixmap, gtk_col, gtk_col, 0, 0)
        win.window.set_cursor(invisible_cursor)

    def get_layout_item_properties(self, lines, offset):
        """get properties for item in layout"""
        d={}
        d['visible'] = (lines[offset].lower() == 'true')
        d['transparent'] = (lines[offset + 1] == '1')
        d['background-col'] = self.get_colour(int(lines[offset + 2]))
        d['text-col'] = self.get_colour(int(lines[offset + 3]))
        d['font'] = lines[offset + 4]
        d['font-bold'] = (lines[offset + 5].lower() == 'true')
        d['font-italic'] = (lines[offset + 6].lower() == 'true')
        d['font-size'] = float(lines[offset + 7])
        align_rot = lines[offset + 8].split(';')
        d['text-align'] = int(align_rot[0])
        d['text-rotation'] = 0
        if len(align_rot) > 1:
            d['text-rotation'] = int(align_rot[1])
        d['x'] = int(lines[offset + 9])
        d['y'] = int(lines[offset + 10])
        d['width'] = int(lines[offset + 11])
        d['height'] = int(lines[offset + 12])
        #done
        return d

    def get_colorbutton_info(self, clr_widget):
        """get gtk.ColorButton widgets current colour in gdk and hex format"""
        clr = clr_widget.get_color()
        hex_clr = '#%s%s%s' % (
            hex(clr.red/256)[2:].rjust(2, '0'),
            hex(clr.green/256)[2:].rjust(2, '0'),
            hex(clr.blue/256)[2:].rjust(2, '0'))
        return clr, hex_clr

    def get_colour(self, col):
        """convert decimal colour into format suitable for gtk colour"""
        hex_col = hex(col)[2:].rjust(6, '0').upper()
        #re-arrange
        hex_col = '#%s%s%s' % (hex_col[4:6], hex_col[2:4], hex_col[0:2])
        return hex_col

    def reverse_get_colour(self, hex_col):
        """reverse get_colour method - convert hex colour (#RRGGBB) into
           wahcade's decimal format"""
        r = int(hex_col[1:3], 16)
        g = int(hex_col[3:5], 16)
        b = int(hex_col[5:7], 16)
        col = (b * 256 * 256) + (g * 256) + r
        return col

    def get_matching_filename(self, file_prefixes, file_formats):
        """return the filename if it exists from given formats & path
              file_prefixes = [(dir_name, filename), ...]
              file_formats = [file_ext1, file_ext2, ...]
        """
        p = re.compile('(\.[^\.]+$)|(\s(\(|\[).+(?<=(\)|\]|\s))\.[^\.]+$)')
        self.wahcade_ini = MameWahIni(os.path.join(CONFIG_DIR, 'wahcade.ini'))
        l = self.wahcade_ini.get('layout')
        fz = self.wahcade_ini.getint('fuzzy_artwork_search')
        #check lower & upper case filenames for each given prefix & format
        for dirname, fp in file_prefixes:
            if fp == '##random##':
                for ff in file_formats:
                    fnl = walk_dir(dirname, False, '*.%s' % ff.lower(), False) + \
                        walk_dir(dirname, False, '*.%s' % ff.upper(), False)
                    #return first valid match
                    for filename in fnl:
                        if os.path.isfile(filename):
                            return filename
            elif fp != '':
                if file_formats != '':
                    # Check if this is a layout
                    if l not in dirname:
                        if fz:
                            # NB: we append a fake extension here to support the regex currently - sairuk
                            #     handles . appearing in filename being treated as an ext
                            fileset = glob.iglob(os.path.join(CONFIG_DIR, dirname, re.sub(p,'',fp + ".fix") + "*"))
                            for filename in fileset:
                                fn = os.path.basename(filename.lower())
                                f = re.sub(p,'',fn)
                                g = re.search(re.escape(f),fp.lower())
                                if f and g is not None:
                                    if f == g.group(0):
                                        return filename
                                else:
                                    self.log_msg(" [ARTWORK] No match for " + fp + " in " + dirname, 1)
                        else:
                            for ff in file_formats:
                                basename = '%s.%s' % (fp, ff)
                                #build list of possible filenames
                                fnl = [os.path.join(dirname, basename),
                                       os.path.join(dirname, basename.lower()),
                                       os.path.join(dirname, basename.upper())]
                                #return first valid match
                                for filename in fnl:
                                    if os.path.isfile(filename):
                                        return filename
                    else:
                        for ff in file_formats:
                            basename = '%s.%s' % (fp, ff)
                            #build list of possible filenames
                            fnl = [os.path.join(dirname, basename),
                                   os.path.join(dirname, basename.lower()),
                                   os.path.join(dirname, basename.upper())]
                            #return first valid match
                            for filename in fnl:
                                if os.path.isfile(filename):
                                    return filename
                                
                else:
                    filename = os.path.join(dirname, fp)
                    if os.path.isfile(filename):
                        return filename
        #done - nothing found
        return ''

    def get_artwork_image(self, img_path, layout_path, game_info, emu_name, artwork_num):
        """check various permutations of file name and return img filename"""
        #list of files to check for
        image_files = [
            (img_path, game_info['rom_name']),
            (img_path, game_info['clone_of']),
            (os.path.join(img_path, game_info['rom_name'].upper()), '##random##'),
            (os.path.join(img_path, game_info['rom_name'].lower()), '##random##'),
            (layout_path, '%s-art%s' % (emu_name, artwork_num)),
            (layout_path, '%s-art' % (emu_name)),
            (layout_path, 'art%s' % artwork_num),
            (layout_path, 'art')]
        #get artwork filename
        art_filename = self.get_matching_filename(
            image_files,
            IMAGE_FILETYPES)
        #still not found an image?
        if art_filename == '':
            #use default empty image
            art_filename = os.path.join(APP_PATH, 'pixmaps', 'empty.png')
        #done
        return art_filename

    def get_video_file(self, video_path, game_info):
        """check various permutations of file name and return video filename"""
        #list of files to check for
        video_files = [
            (video_path, game_info['rom_name']),
            (video_path, game_info['clone_of'])]
        #get vid filename
        vid_filename = self.get_matching_filename(
            video_files,
            MOVIE_FILETYPES)
        #done
        return vid_filename

    def get_scaled_pixbuf(self, img, img_filename, keep_aspect, missing_img=None, rotate=0):
        """get a pixbuf with image from filename (scaled to fit)"""
        #get image widget size
        img_width, img_height = img.size_request()
        #load image
        self.anim = 0
        try:
            if rotate is not 0 and pil_imported:
                pb = self.pil_image_to_pixbuf(img_filename, rotate)
            else:
                pb = gtk.gdk.PixbufAnimation(img_filename)
                self.anim = 1
                if pb.is_static_image():
                    del pb
                    pb = gtk.gdk.pixbuf_new_from_file(img_filename)
                    self.anim = 0
        except IOError:
            #load empty image
            if not missing_img:
                missing_img = os.path.join(APP_PATH, 'pixmaps', 'empty.png')
            pb = gtk.gdk.pixbuf_new_from_file(missing_img)
        #calc image scale
        img_scale_x = float(img_width) / float(pb.get_width())
        img_scale_y = float(img_height) / float(pb.get_height())
        #scale to width or height
        if keep_aspect:
            if (pb.get_height()) * img_scale_x > img_height:
                #scale to height
                new_pb_width = int(float(pb.get_width()) * img_scale_y)
                new_pb_height = int(float(pb.get_height()) * img_scale_y)
            else:
                #scale to width
                new_pb_width = int(float(pb.get_width()) * img_scale_x)
                new_pb_height = int(float(pb.get_height()) * img_scale_x)
        else:
            new_pb_width = img_width
            new_pb_height = img_height
        #scale artwork to display size
        if self.anim == 1:
            scaled_pb = pb
        else:
            scaled_pb = pb.scale_simple(new_pb_width, new_pb_height, gtk.gdk.INTERP_HYPER)
        #set video width & height
        if img == self.video_artwork_widget:
            self.video_width = new_pb_width
            self.video_height = new_pb_height
        #done
        del pb
        return scaled_pb

    def display_scaled_image(self, img, img_filename, keep_aspect, rotate=0):
        """load given image widget with filename (scaled to fit)"""
        pb = self.get_scaled_pixbuf(img, img_filename, keep_aspect, rotate=rotate)
        if self.anim == 1:
            img.set_from_animation(pb)
        else:
            img.set_from_pixbuf(pb)
        del pb

    def do_events(self):
        """process any outstanding gtk events"""
        while gtk.events_pending():
            gtk.main_iteration(False)

    def get_path(self, check_path):
        """return a given path, with user expansion"""
        if check_path:
            if os.path.exists(os.path.expanduser(check_path)):
                check_path = os.path.normcase(os.path.expanduser(check_path))
        #done
        return check_path

    def show_about_dialog(self, app_name, config_dir):
        """about dialog"""
        #open controller ini file
        self.ctrlr_ini = MameWahIni(os.path.join(config_dir, 'ctrlr', 'default.ini'), 'ctrlr')
        #create about dialog
        dlg = gtk.AboutDialog()
        dlg.set_name(app_name)
        dlg.set_version('\n%s "%s"' % (VERSION, VERSION_NAME))
        dlg.set_logo(gtk.gdk.pixbuf_new_from_file(
            os.path.join(APP_PATH, 'pixmaps', 'wahcade-logo.png')))
        gtk.about_dialog_set_url_hook(self.show_website, None)
        dlg.set_website('http:///www.anti-particle.com/wahcade.shtml')
        dlg.set_website_label('www.anti-particle.com/wahcade')
        dlg.set_authors([
            'Andy Balcombe', 'sairuk',
            'Bug Reports and Patches:',
                '  Sylvain Fauveau', '  Robbforce', '  Jim Merullo',
                '  SeTTleR', '  Mike Crawford', '  Mike Schwartz',
                '  Nellistc', '  Captbaritone', '  Delphipool', '  3NF',
                '  Zerodiv', '  Natrix', '  Bonzo', '  Battlecat', '  Krisbee',
                '  Buks', '  KillsTheWeak', '  Martin Kalitis', '  Zerojay',
                '  Dave Baer', '  Spudgunman', '  RomKnight', '  Jason Carter',
                '  Zombie', '  Pinball Wizard', '  hamelg', '  3vi1',
                '  Vítor Baptista', '  Enrico Magrella', 'zagadka',
                '  and anyone I\'ve forgotten...', '',
            'Translations:',
                '  de: SeTTleR', '  es: Nicolás Álvarez',
                '  fr: Sylvain Faveau', '  it: Diego Pierotto',
                '  sv: Daniel Nylander', '',
            'bdist_debian.py: Gene Cash', '',
            ])
        dlg.set_artists(['Andy Balcombe', 'Buks', 'Battlecat'])
        dlg.set_copyright('%s 2005-2010 Andy Balcombe' % (
            unichr(169)).encode("utf-8"))
        dlg.set_comments('Thanks to:\nMinWah and also the Mame / xMame team')
        dlg.set_translator_credits(_('translator-credits'))
        dlg.set_license(open(os.path.join(APP_PATH, 'doc', 'COPYING')).read())
        dlg.connect('key_press_event', self.on_dlgAbout_key_press)
        dlg.run()
        dlg.hide()

    def on_dlgAbout_key_press(self, dlg, event, *args):
        """keyboard pressed on about dialog - close it"""
        if event.type == gtk.gdk.KEY_PRESS:
            #keyboard pressed, get gtk keyname
            keyname = gtk.gdk.keyval_name(event.keyval).lower()
            if keyname not in mamewah_keys:
                return
            #get mamewah keyname
            mw_keys = mamewah_keys[keyname]
            if mw_keys == []:
                return
            #get mamewah function from key
            for mw_key in mw_keys:
                mw_functions = self.ctrlr_ini.reverse_get(mw_key)
                if mw_functions:
                    break
            #check key
            for mw_func in mw_functions:
                if mw_func in ['LAUNCH_GAME', 'EXIT_TO_WINDOWS']:
                    #send close signal
                    dlg.response(gtk.RESPONSE_CLOSE)

    def show_website(self, dlg, link, data):
        """display web site from about dialog"""
        webbrowser.open(link)

    def invert_dictionary_with_lists(self, d):
        """inverts a dictionary that contains lists"""
        return dict((v, k) for k in d for v in d[k])

    def make_evb_widget(self, widget):
        """create an event box and add the given widget to it"""
        evb = gtk.EventBox()
        #evb.show()
        evb.add(widget)
        return evb

    def copy_user_config(self, copymode='update'):
        """update the user's config dir (e.g. ~/.wahcade) with any missing
           files from wahcade/config.dist"""
        if copymode == 'all':
            #copy ALL config files
            shutil.copytree(
                os.path.join(APP_PATH, 'config.dist'),
                CONFIG_DIR)
        else:
            #update the config files
            self._copytree(
                os.path.join(APP_PATH, 'config.dist'),
                CONFIG_DIR)

    def _copytree(self, src, dst):
        """copy files from src to dst"""
        names = os.listdir(src)
        if not os.path.exists(dst):
            os.mkdir(dst)
        for name in names:
            srcname = os.path.join(src, name)
            dstname = os.path.join(dst, name)
            try:
                if os.path.isdir(srcname):
                    self._copytree(srcname, dstname)
                else:
                    if not os.path.exists(dstname):
                        if 'config.dist/ini/' not in srcname:
                            #create file if it doesn't exist already
                            shutil.copy2(srcname, dstname)
            except IOError:
                pass

    def pil_image_to_pixbuf(self, image_fn, angle):
        """use Python Image Library (PIL) to load an image, rotate it, and return as a pixbuf)
        """
        pixbuf = None
        if os.path.isfile(image_fn):
            pil_image = PIL.Image.open(image_fn)
            if angle is not 0:
                pil_image = pil_image.rotate(angle,PIL.Image.BICUBIC,1)
            fd = StringIO.StringIO()
            pil_image.save(fd, "png")
            contents = fd.getvalue()
            fd.close()
            loader = gtk.gdk.PixbufLoader("png")
            loader.write(contents, len(contents))
            pixbuf = loader.get_pixbuf()
            loader.close()
        #done
        return pixbuf

    def set_busy_cursor(self, win):
        """set mouse to busy cursor"""
        win.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
        self.do_events()

    def set_normal_cursor(self, win):
        """set mouse to arrow cursor"""
        win.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.ARROW))
        self.do_events()

    def wait_with_events(self, num_seconds):
        """pause for a given amount of time"""
        time_start = time.time()
        while True:
            self.do_events()
            if (time_start + num_seconds) < time.time():
                break

    # return_listnum
    # returns digits included in string after a dash
    #
    def return_listnum(self, str, regex="(?<=-)\d+"):
        """return regex result from string"""
        m = re.search(regex,str)
        if m is not None:
            return int(m.group(0))

    # build_filelist
    # returns sorted array of files numbers matching regex.
    #
    # defaults
    # type, type of list, required
    # ext, *.ini
    # regex, (?<=-)\d+ [matches 0 in mame-0.ini]
    # emu, current emu name
    # sep, sparator used in file, default is none
    #
    def build_filelist(self, type, ext="ini", regex="(?<=-)\d+", emu="", sep=""):
        """return array of files numbers matching regex value"""
        filelist = []
        fileset = glob.glob(os.path.join(CONFIG_DIR, ext, emu + sep + '*.' + ext))
        for file in fileset:
            m = re.search(regex,file)
            if m is not None:
                if type == "int":
                    filelist.append(self.return_listnum(file))
                elif type == "glist":
                    if os.path.isfile(file):
                        list_ini = MameWahIni(file)
                        filelist.append('%s: %s' % (self.return_listnum(file),list_ini.get('list_title')))
                else:
                    filelist.append(file)
        filelist.sort()
        return filelist
    
    
    # buildemulist
    # returns array of available emulators
    #
    def buildemulist(self):
        emu_lists = []
        emu_ini_files = self.build_filelist("", "ini", "(.*(?<!=-))")
        for emu_ini in emu_ini_files:
            ini = MameWahIni(emu_ini)
            if not ini.has_option('list_title'):
                emu_lists.append(
                    [ini.get('emulator_title'),
                     os.path.splitext(os.path.basename(emu_ini))[0],ini])
        return emu_lists
    
    # buildartlist
    # returns array of available artwork
    #
    def buildartlist(self, dirname):
        art_lists = []
        art_lists = glob.glob(os.path.join(CONFIG_DIR, dirname, "*"))
        return art_lists
    

    # log_msg
    # writes log files
    #
    def log_msg(self, message, type='X'):
        """writing application log file"""
        # To be used to write log files in the future
        # Set Date & Time        
        mytime = time.asctime( time.localtime(time.time()) )
        pmessage = "[" + str(mytime) + "]: " + str(message)
        
        # Print message to location
        #    0 = stdout
        #    1 = debug messages
        if type == 0:
            print(message)   
        elif type == 1:
            pmessage = "[" + str(mytime) + "]: [DEBUG] " + str(message)
        else:
            pass
        # All messages are written to wahcade.log
        try:
            f = open(self.log_filename, 'a')
            f.write(pmessage + '\n')
            f.close()
        except:
            pass 


    def auth_twitter(self):
        try:
            tw_error = []
            if self.tw_oath_ckey == '':
                tw_error.append('consumer_key')
            if self.tw_oath_csecret == '':
                tw_error.append('consumer_secret')
            if self.tw_oath_akey == '':
                tw_error.append('access_key')
            if self.tw_oath_asecret == '':
                tw_error.append('access_key')

            if len(tw_error) > 0:
                twitter_enabled = False
                self.log_msg('[TWITTER] support disabled due to missing options')
                for tw_error in tw_error:
                    self.log_msg('[TWITTER] %s cannot be blank in wahcade.ini, details available at https://dev.twitter.com/' % tw_error)
                return

            self.log_msg(('[TWITTER] Beginning OAuthentication'))
            auth = tweepy.OAuthHandler(self.tw_oath_ckey,self.tw_oath_csecret)
            auth.set_access_token(self.tw_oath_akey, self.tw_oath_asecret)
            self.tw_api = tweepy.API(auth)
            if not self.tw_api.verify_credentials():
                self.log_msg('[TWITTER] Error! OAuthentication failure')
                self.tw_api = None
            else:
                self.log_msg('[TWITTER] Logged in as: %s' % self.tw_api.me().name)
            return self.tw_api
        except tweepy.TweepError:
            return None

    def post_tweet(self,msg):
        try:
            self.tw_api.update_status(msg)
            self.log_msg('[TWITTER] tweeting: %s' % msg)
            return 'Post Tweet Success!'
        except tweepy.TweepError:
            return 'Post Tweet Failed!'

    def procmsg(self,msg):
        if msg:
            # Build Message based on data available
            msg_opts = {}
            msg_opts["%r"]= self.lsGames[self.sclGames.get_selected()][GL_ROM_NAME]
            msg_opts["%n"]= self.lsGames[self.sclGames.get_selected()][GL_GAME_NAME]
            msg_opts["%y"]= self.lsGames[self.sclGames.get_selected()][GL_YEAR]
            msg_opts["%m"]= self.lsGames[self.sclGames.get_selected()][GL_MANUFACTURER]
            msg_opts["%c"]= self.lsGames[self.sclGames.get_selected()][GL_CATEGORY]
            msg_opts["%d"]= self.lsGames[self.sclGames.get_selected()][GL_DISPLAY_TYPE]
            msg_opts["%s"]= self.lsGames[self.sclGames.get_selected()][GL_SCREEN_TYPE]
            msg_opts["%e"]= self.emu_ini.get('emulator_title')
            msg_opts["%g"]= self.current_list_ini.get('list_title')
            # Make substitution in msg string
            for i in msg_opts.iteritems():
                msg = msg.replace(i[0],i[1])
            msg = msg + " " + time.strftime("%H:%M:%S") + " " + self.tw_ctags
        return msg
Ejemplo n.º 2
0
class WahCade:
    """Common functions for Wah!Cade"""
    def __init__(self):
        """initialise common wahcade class"""
        #set default icon for windows
        gtk.window_set_default_icon_from_file(
            os.path.join(APP_PATH, 'pixmaps', 'wahcade.png'))
        ### LOGFILE
        if os.path.exists(CONFIG_DIR):
            self.log_filename = os.path.join(CONFIG_DIR, 'wahcade.log')
            try:
                f = open(self.log_filename, 'w')
                self.log_msg(
                    "//======================= NEW LOG RUN =======================//"
                )
                f.close
            except:
                print "ERROR opening LOG FILE, %s, check for orphaned processes" % self.log_filename

    def hide_mouse_cursor(self, win):
        """hide mouse cursor"""
        gtk_col = gtk.gdk.Color()
        pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
        invisible_cursor = gtk.gdk.Cursor(pixmap, pixmap, gtk_col, gtk_col, 0,
                                          0)
        win.window.set_cursor(invisible_cursor)

    def get_layout_item_properties(self, lines, offset):
        """get properties for item in layout"""
        d = {}
        d['visible'] = (lines[offset].lower() == 'true')
        d['transparent'] = (lines[offset + 1] == '1')
        d['background-col'] = self.get_colour(int(lines[offset + 2]))
        d['text-col'] = self.get_colour(int(lines[offset + 3]))
        d['font'] = lines[offset + 4]
        d['font-bold'] = (lines[offset + 5].lower() == 'true')
        d['font-italic'] = (lines[offset + 6].lower() == 'true')
        d['font-size'] = float(lines[offset + 7])
        align_rot = lines[offset + 8].split(';')
        d['text-align'] = int(align_rot[0])
        d['text-rotation'] = 0
        if len(align_rot) > 1:
            d['text-rotation'] = int(align_rot[1])
        d['x'] = int(lines[offset + 9])
        d['y'] = int(lines[offset + 10])
        d['width'] = int(lines[offset + 11])
        d['height'] = int(lines[offset + 12])
        #done
        return d

    def get_colorbutton_info(self, clr_widget):
        """get gtk.ColorButton widgets current colour in gdk and hex format"""
        clr = clr_widget.get_color()
        hex_clr = '#%s%s%s' % (hex(
            clr.red / 256)[2:].rjust(2, '0'), hex(clr.green / 256)[2:].rjust(
                2, '0'), hex(clr.blue / 256)[2:].rjust(2, '0'))
        return clr, hex_clr

    def get_colour(self, col):
        """convert decimal colour into format suitable for gtk colour"""
        hex_col = hex(col)[2:].rjust(6, '0').upper()
        #re-arrange
        hex_col = '#%s%s%s' % (hex_col[4:6], hex_col[2:4], hex_col[0:2])
        return hex_col

    def reverse_get_colour(self, hex_col):
        """reverse get_colour method - convert hex colour (#RRGGBB) into
           wahcade's decimal format"""
        r = int(hex_col[1:3], 16)
        g = int(hex_col[3:5], 16)
        b = int(hex_col[5:7], 16)
        col = (b * 256 * 256) + (g * 256) + r
        return col

    def get_matching_filename(self, file_prefixes, file_formats):
        """return the filename if it exists from given formats & path
              file_prefixes = [(dir_name, filename), ...]
              file_formats = [file_ext1, file_ext2, ...]
        """
        p = re.compile('(\.[^\.]+$)|(\s(\(|\[).+(?<=(\)|\]|\s))\.[^\.]+$)')
        self.wahcade_ini = MameWahIni(os.path.join(CONFIG_DIR, 'wahcade.ini'))
        l = self.wahcade_ini.get('layout')
        fz = self.wahcade_ini.getint('fuzzy_artwork_search')
        #check lower & upper case filenames for each given prefix & format
        for dirname, fp in file_prefixes:
            if fp == '##random##':
                for ff in file_formats:
                    fnl = walk_dir(dirname, False, '*.%s' % ff.lower(), False) + \
                        walk_dir(dirname, False, '*.%s' % ff.upper(), False)
                    #return first valid match
                    for filename in fnl:
                        if os.path.isfile(filename):
                            return filename
            elif fp != '':
                if file_formats != '':
                    # Check if this is a layout
                    if l not in dirname:
                        if fz:
                            # NB: we append a fake extension here to support the regex currently - sairuk
                            #     handles . appearing in filename being treated as an ext
                            fileset = glob.iglob(
                                os.path.join(CONFIG_DIR, dirname,
                                             re.sub(p, '', fp + ".fix") + "*"))
                            for filename in fileset:
                                fn = os.path.basename(filename.lower())
                                f = re.sub(p, '', fn)
                                g = re.search(re.escape(f), fp.lower())
                                if f and g is not None:
                                    if f == g.group(0):
                                        return filename
                                else:
                                    self.log_msg(
                                        " [ARTWORK] No match for " + fp +
                                        " in " + dirname, 1)
                        else:
                            for ff in file_formats:
                                basename = '%s.%s' % (fp, ff)
                                #build list of possible filenames
                                fnl = [
                                    os.path.join(dirname, basename),
                                    os.path.join(dirname, basename.lower()),
                                    os.path.join(dirname, basename.upper())
                                ]
                                #return first valid match
                                for filename in fnl:
                                    if os.path.isfile(filename):
                                        return filename
                    else:
                        for ff in file_formats:
                            basename = '%s.%s' % (fp, ff)
                            #build list of possible filenames
                            fnl = [
                                os.path.join(dirname, basename),
                                os.path.join(dirname, basename.lower()),
                                os.path.join(dirname, basename.upper())
                            ]
                            #return first valid match
                            for filename in fnl:
                                if os.path.isfile(filename):
                                    return filename

                else:
                    filename = os.path.join(dirname, fp)
                    if os.path.isfile(filename):
                        return filename
        #done - nothing found
        return ''

    def get_artwork_image(self, img_path, layout_path, game_info, emu_name,
                          artwork_num):
        """check various permutations of file name and return img filename"""
        #list of files to check for
        image_files = [(img_path, game_info['rom_name']),
                       (img_path, game_info['clone_of']),
                       (os.path.join(img_path, game_info['rom_name'].upper()),
                        '##random##'),
                       (os.path.join(img_path, game_info['rom_name'].lower()),
                        '##random##'),
                       (layout_path, '%s-art%s' % (emu_name, artwork_num)),
                       (layout_path, '%s-art' % (emu_name)),
                       (layout_path, 'art%s' % artwork_num),
                       (layout_path, 'art')]
        #get artwork filename
        art_filename = self.get_matching_filename(image_files, IMAGE_FILETYPES)
        #still not found an image?
        if art_filename == '':
            #use default empty image
            art_filename = os.path.join(APP_PATH, 'pixmaps', 'empty.png')
        #done
        return art_filename

    def get_video_file(self, video_path, game_info):
        """check various permutations of file name and return video filename"""
        #list of files to check for
        video_files = [(video_path, game_info['rom_name']),
                       (video_path, game_info['clone_of'])]
        #get vid filename
        vid_filename = self.get_matching_filename(video_files, MOVIE_FILETYPES)
        #done
        return vid_filename

    def get_scaled_pixbuf(self,
                          img,
                          img_filename,
                          keep_aspect,
                          missing_img=None,
                          rotate=0):
        """get a pixbuf with image from filename (scaled to fit)"""
        #get image widget size
        img_width, img_height = img.size_request()
        #load image
        self.anim = 0
        try:
            if rotate is not 0 and pil_imported:
                pb = self.pil_image_to_pixbuf(img_filename, rotate)
            else:
                pb = gtk.gdk.PixbufAnimation(img_filename)
                self.anim = 1
                if pb.is_static_image():
                    del pb
                    pb = gtk.gdk.pixbuf_new_from_file(img_filename)
                    self.anim = 0
        except IOError:
            #load empty image
            if not missing_img:
                missing_img = os.path.join(APP_PATH, 'pixmaps', 'empty.png')
            pb = gtk.gdk.pixbuf_new_from_file(missing_img)
        #calc image scale
        img_scale_x = float(img_width) / float(pb.get_width())
        img_scale_y = float(img_height) / float(pb.get_height())
        #scale to width or height
        if keep_aspect:
            if (pb.get_height()) * img_scale_x > img_height:
                #scale to height
                new_pb_width = int(float(pb.get_width()) * img_scale_y)
                new_pb_height = int(float(pb.get_height()) * img_scale_y)
            else:
                #scale to width
                new_pb_width = int(float(pb.get_width()) * img_scale_x)
                new_pb_height = int(float(pb.get_height()) * img_scale_x)
        else:
            new_pb_width = img_width
            new_pb_height = img_height
        #scale artwork to display size
        if self.anim == 1:
            scaled_pb = pb
        else:
            scaled_pb = pb.scale_simple(new_pb_width, new_pb_height,
                                        gtk.gdk.INTERP_HYPER)
        #set video width & height
        if img == self.video_artwork_widget:
            self.video_width = new_pb_width
            self.video_height = new_pb_height
        #done
        del pb
        return scaled_pb

    def display_scaled_image(self, img, img_filename, keep_aspect, rotate=0):
        """load given image widget with filename (scaled to fit)"""
        pb = self.get_scaled_pixbuf(img,
                                    img_filename,
                                    keep_aspect,
                                    rotate=rotate)
        if self.anim == 1:
            img.set_from_animation(pb)
        else:
            img.set_from_pixbuf(pb)
        del pb

    def do_events(self):
        """process any outstanding gtk events"""
        while gtk.events_pending():
            gtk.main_iteration(False)

    def get_path(self, check_path):
        """return a given path, with user expansion"""
        if check_path:
            if os.path.exists(os.path.expanduser(check_path)):
                check_path = os.path.normcase(os.path.expanduser(check_path))
        #done
        return check_path

    def show_about_dialog(self, app_name, config_dir):
        """about dialog"""
        #open controller ini file
        self.ctrlr_ini = MameWahIni(
            os.path.join(config_dir, 'ctrlr', 'default.ini'), 'ctrlr')
        #create about dialog
        dlg = gtk.AboutDialog()
        dlg.set_name(app_name)
        dlg.set_version('\n%s "%s"' % (VERSION, VERSION_NAME))
        dlg.set_logo(
            gtk.gdk.pixbuf_new_from_file(
                os.path.join(APP_PATH, 'pixmaps', 'wahcade-logo.png')))
        gtk.about_dialog_set_url_hook(self.show_website, None)
        dlg.set_website('http:///www.anti-particle.com/wahcade.shtml')
        dlg.set_website_label('www.anti-particle.com/wahcade')
        dlg.set_authors([
            'Andy Balcombe',
            'sairuk',
            'Bug Reports and Patches:',
            '  Sylvain Fauveau',
            '  Robbforce',
            '  Jim Merullo',
            '  SeTTleR',
            '  Mike Crawford',
            '  Mike Schwartz',
            '  Nellistc',
            '  Captbaritone',
            '  Delphipool',
            '  3NF',
            '  Zerodiv',
            '  Natrix',
            '  Bonzo',
            '  Battlecat',
            '  Krisbee',
            '  Buks',
            '  KillsTheWeak',
            '  Martin Kalitis',
            '  Zerojay',
            '  Dave Baer',
            '  Spudgunman',
            '  RomKnight',
            '  Jason Carter',
            '  Zombie',
            '  Pinball Wizard',
            '  hamelg',
            '  3vi1',
            '  Vítor Baptista',
            '  Enrico Magrella',
            'zagadka',
            '  and anyone I\'ve forgotten...',
            '',
            'Translations:',
            '  de: SeTTleR',
            '  es: Nicolás Álvarez',
            '  fr: Sylvain Faveau',
            '  it: Diego Pierotto',
            '  sv: Daniel Nylander',
            '',
            'bdist_debian.py: Gene Cash',
            '',
        ])
        dlg.set_artists(['Andy Balcombe', 'Buks', 'Battlecat'])
        dlg.set_copyright('%s 2005-2010 Andy Balcombe' %
                          (unichr(169)).encode("utf-8"))
        dlg.set_comments('Thanks to:\nMinWah and also the Mame / xMame team')
        dlg.set_translator_credits(_('translator-credits'))
        dlg.set_license(open(os.path.join(APP_PATH, 'doc', 'COPYING')).read())
        dlg.connect('key_press_event', self.on_dlgAbout_key_press)
        dlg.run()
        dlg.hide()

    def on_dlgAbout_key_press(self, dlg, event, *args):
        """keyboard pressed on about dialog - close it"""
        if event.type == gtk.gdk.KEY_PRESS:
            #keyboard pressed, get gtk keyname
            keyname = gtk.gdk.keyval_name(event.keyval).lower()
            if keyname not in mamewah_keys:
                return
            #get mamewah keyname
            mw_keys = mamewah_keys[keyname]
            if mw_keys == []:
                return
            #get mamewah function from key
            for mw_key in mw_keys:
                mw_functions = self.ctrlr_ini.reverse_get(mw_key)
                if mw_functions:
                    break
            #check key
            for mw_func in mw_functions:
                if mw_func in ['LAUNCH_GAME', 'EXIT_TO_WINDOWS']:
                    #send close signal
                    dlg.response(gtk.RESPONSE_CLOSE)

    def show_website(self, dlg, link, data):
        """display web site from about dialog"""
        webbrowser.open(link)

    def invert_dictionary_with_lists(self, d):
        """inverts a dictionary that contains lists"""
        return dict((v, k) for k in d for v in d[k])

    def make_evb_widget(self, widget):
        """create an event box and add the given widget to it"""
        evb = gtk.EventBox()
        #evb.show()
        evb.add(widget)
        return evb

    def copy_user_config(self, copymode='update'):
        """update the user's config dir (e.g. ~/.wahcade) with any missing
           files from wahcade/config.dist"""
        if copymode == 'all':
            #copy ALL config files
            shutil.copytree(os.path.join(APP_PATH, 'config.dist'), CONFIG_DIR)
        else:
            #update the config files
            self._copytree(os.path.join(APP_PATH, 'config.dist'), CONFIG_DIR)

    def _copytree(self, src, dst):
        """copy files from src to dst"""
        names = os.listdir(src)
        if not os.path.exists(dst):
            os.mkdir(dst)
        for name in names:
            srcname = os.path.join(src, name)
            dstname = os.path.join(dst, name)
            try:
                if os.path.isdir(srcname):
                    self._copytree(srcname, dstname)
                else:
                    if not os.path.exists(dstname):
                        if 'config.dist/ini/' not in srcname:
                            #create file if it doesn't exist already
                            shutil.copy2(srcname, dstname)
            except IOError:
                pass

    def pil_image_to_pixbuf(self, image_fn, angle):
        """use Python Image Library (PIL) to load an image, rotate it, and return as a pixbuf)
        """
        pixbuf = None
        if os.path.isfile(image_fn):
            pil_image = PIL.Image.open(image_fn)
            if angle is not 0:
                pil_image = pil_image.rotate(angle, PIL.Image.BICUBIC, 1)
            fd = StringIO.StringIO()
            pil_image.save(fd, "png")
            contents = fd.getvalue()
            fd.close()
            loader = gtk.gdk.PixbufLoader("png")
            loader.write(contents, len(contents))
            pixbuf = loader.get_pixbuf()
            loader.close()
        #done
        return pixbuf

    def set_busy_cursor(self, win):
        """set mouse to busy cursor"""
        win.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
        self.do_events()

    def set_normal_cursor(self, win):
        """set mouse to arrow cursor"""
        win.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.ARROW))
        self.do_events()

    def wait_with_events(self, num_seconds):
        """pause for a given amount of time"""
        time_start = time.time()
        while True:
            self.do_events()
            if (time_start + num_seconds) < time.time():
                break

    # return_listnum
    # returns digits included in string after a dash
    #
    def return_listnum(self, str, regex="(?<=-)\d+"):
        """return regex result from string"""
        m = re.search(regex, str)
        if m is not None:
            return int(m.group(0))

    # build_filelist
    # returns sorted array of files numbers matching regex.
    #
    # defaults
    # type, type of list, required
    # ext, *.ini
    # regex, (?<=-)\d+ [matches 0 in mame-0.ini]
    # emu, current emu name
    # sep, sparator used in file, default is none
    #
    def build_filelist(self,
                       type,
                       ext="ini",
                       regex="(?<=-)\d+",
                       emu="",
                       sep=""):
        """return array of files numbers matching regex value"""
        filelist = []
        fileset = glob.glob(
            os.path.join(CONFIG_DIR, ext, emu + sep + '*.' + ext))
        for file in fileset:
            m = re.search(regex, file)
            if m is not None:
                if type == "int":
                    filelist.append(self.return_listnum(file))
                elif type == "glist":
                    if os.path.isfile(file):
                        list_ini = MameWahIni(file)
                        filelist.append('%s: %s' %
                                        (self.return_listnum(file),
                                         list_ini.get('list_title')))
                else:
                    filelist.append(file)
        filelist.sort()
        return filelist

    # buildemulist
    # returns array of available emulators
    #
    def buildemulist(self):
        emu_lists = []
        emu_ini_files = self.build_filelist("", "ini", "(.*(?<!=-))")
        for emu_ini in emu_ini_files:
            ini = MameWahIni(emu_ini)
            if not ini.has_option('list_title'):
                emu_lists.append([
                    ini.get('emulator_title'),
                    os.path.splitext(os.path.basename(emu_ini))[0], ini
                ])
        return emu_lists

    # buildartlist
    # returns array of available artwork
    #
    def buildartlist(self, dirname):
        art_lists = []
        art_lists = glob.glob(os.path.join(CONFIG_DIR, dirname, "*"))
        return art_lists

    # log_msg
    # writes log files
    #
    def log_msg(self, message, type='X'):
        """writing application log file"""
        # To be used to write log files in the future
        # Set Date & Time
        mytime = time.asctime(time.localtime(time.time()))
        pmessage = "[" + str(mytime) + "]: " + str(message)

        # Print message to location
        #    0 = stdout
        #    1 = debug messages
        if type == 0:
            print(message)
        elif type == 1:
            pmessage = "[" + str(mytime) + "]: [DEBUG] " + str(message)
        else:
            pass
        # All messages are written to wahcade.log
        try:
            f = open(self.log_filename, 'a')
            f.write(pmessage + '\n')
            f.close()
        except:
            pass

    def auth_twitter(self):
        tw_error = []
        if self.tw_oath_ckey == '':
            tw_error.append('consumer_key')
        if self.tw_oath_csecret == '':
            tw_error.append('consumer_secret')
        if self.tw_oath_akey == '':
            tw_error.append('access_key')
        if self.tw_oath_asecret == '':
            tw_error.append('access_key')

        if len(tw_error) > 0:
            twitter_enabled = False
            self.log_msg('[TWITTER] support disabled due to missing options')
            for tw_error in tw_error:
                self.log_msg(
                    '[TWITTER] %s cannot be blank in wahcade.ini, details available at https://dev.twitter.com/'
                    % tw_error)
            return

        self.log_msg(('[TWITTER] Beginning OAuthentication'))
        auth = tweepy.OAuthHandler(self.tw_oath_ckey, self.tw_oath_csecret)
        auth.set_access_token(self.tw_oath_akey, self.tw_oath_asecret)
        self.tw_api = tweepy.API(auth)
        if not self.tw_api.verify_credentials():
            self.log_msg('[TWITTER] Error! OAuthentication failure')
            self.tw_api = None
        else:
            self.log_msg('[TWITTER] Logged in as: %s' % self.tw_api.me().name)
        return self.tw_api

    def post_tweet(self, msg):
        try:
            self.tw_api.update_status(msg)
            self.log_msg('[TWITTER] tweeting: %s' % msg)
            return 'Post Tweet Success!'
        except tweepy.TweepError:
            return 'Post Tweet Failed!'

    def procmsg(self, msg):
        if msg:
            # Build Message based on data available
            msg_opts = {}
            msg_opts["%r"] = self.lsGames[
                self.sclGames.get_selected()][GL_ROM_NAME]
            msg_opts["%n"] = self.lsGames[
                self.sclGames.get_selected()][GL_GAME_NAME]
            msg_opts["%y"] = self.lsGames[
                self.sclGames.get_selected()][GL_YEAR]
            msg_opts["%m"] = self.lsGames[
                self.sclGames.get_selected()][GL_MANUFACTURER]
            msg_opts["%c"] = self.lsGames[
                self.sclGames.get_selected()][GL_CATEGORY]
            msg_opts["%d"] = self.lsGames[
                self.sclGames.get_selected()][GL_DISPLAY_TYPE]
            msg_opts["%s"] = self.lsGames[
                self.sclGames.get_selected()][GL_SCREEN_TYPE]
            msg_opts["%e"] = self.emu_ini.get('emulator_title')
            msg_opts["%g"] = self.current_list_ini.get('list_title')
            # Make substitution in msg string
            for i in msg_opts.iteritems():
                msg = msg.replace(i[0], i[1])
            msg = msg + " #mahcade " + self.tw_ctags
        return msg
Ejemplo n.º 3
0
class WinSetup(GladeSupport, WahCade):
    """wahcade setup - main window"""

    def __init__(self, glade_filename, window_name, config_opts, config_args):
        """build the window"""
        WahCade.__init__(self)
        GladeSupport.__init__(self, glade_filename, window_name, APP_NAME)
        #command-line options
        self.config_opts = config_opts
        #set default config location (create / update as necessary)
        self.config_dir = CONFIG_DIR
        if not os.path.exists(self.config_dir):
            self.copy_user_config('all')
        else:
            #update current config
            self.copy_user_config()
        #keys list
        self.tvwKeys, self.lsKeys, self.tvwsKeys = self.setup_treeview(
            columns = ['Function', 'Key'],
            column_types = [gobject.TYPE_STRING, gobject.TYPE_STRING],
            container = self.scwKeys,
            resizeable_cols = False)
        self.lsKeys.set_sort_column_id(0, gtk.SORT_ASCENDING)
        self.tvwKeys.connect('row-activated', self.on_tvwKeys_row_activated)
        self.tvwKeys.set_tooltip_text(_('Double-Click a row to change a Key...'))
        #set max width for keys column (stops window getting too wide)
        col = self.tvwKeys.get_column(1)
        col.set_max_width(200)
        #get ini files
        self.wahcade_ini = MameWahIni(os.path.join(self.config_dir, 'wahcade.ini'))
        self.histview_ini = MameWahIni(os.path.join(self.config_dir, 'histview.ini'))
        self.cpviewer_ini = MameWahIni(os.path.join(self.config_dir, 'cpviewer.ini'))
        self.ctrlr_ini = MameWahIni(os.path.join(self.config_dir, 'ctrlr', 'default.ini'), 'ctrlr')
        #emu stuff
        self.emu_list_gen_types = [
            [['rom_folder'], 'Rom Directory'],
            [['rom_folder_vs_listxml', 'list_xml'], 'XML File'],
            [['rom_folder_vs_dat_file', 'dat_file'], 'DAT File']]
        self.emu_scrsave_types = [
            ['blank_screen', 'Blank Screen'],
            ['slideshow', 'Slide Show'],
            ['movie', 'Movies'],
            ['launch_scr', 'Launch External Screen Saver']]
        self.emu_list_types = [
            ['normal', 'Normal'],
            ['most_played', 'Most Played'],
            ['longest_played', 'Longest Played']]
        self.music_movie_mix = [
            ['mute_movies', 'Mute Movies'],
            ['merge', 'Mix with Music']]
        self.emu_artwork_txe = [
            self.txeEmuArt1, self.txeEmuArt2, self.txeEmuArt3, self.txeEmuArt4,
            self.txeEmuArt5, self.txeEmuArt6, self.txeEmuArt7, self.txeEmuArt8,
            self.txeEmuArt9, self.txeEmuArt10]
        self.emu_artwork_btn = [
            self.btnEmuArt1, self.btnEmuArt2, self.btnEmuArt3, self.btnEmuArt4,
            self.btnEmuArt5, self.btnEmuArt6, self.btnEmuArt7, self.btnEmuArt8,
            self.btnEmuArt9, self.btnEmuArt10]
        #setup combo boxes
        self.setup_combo_box(self.cboEmuScrSaver, [r[1] for r in self.emu_scrsave_types])
        self.setup_combo_box(self.cboEmuListGen, [r[1] for r in self.emu_list_gen_types])
        self.setup_combo_box(self.cboEmuListType, [r[1] for r in self.emu_list_types])
        self.setup_combo_box(self.cboWCMovieMix, [r[1] for r in self.music_movie_mix])
        #global joy
        self.joystick = joystick.joystick()
        self.joystick.use_all_controls()
        #get default window size & pos
        self.do_events()
        w, h = self.wahcade_ini.get('setup_window_size', 'default', '400x400').split('x')
        self.winSetup.resize(width=int(w), height=int(h))
        #load settings
        self.load_settings()
        self.setup_altered = False
        #set icon sizes
        settings = gtk.settings_get_default()
        settings.set_string_property('gtk-icon-sizes', 'gtk-button=16,16', '')

    def on_winSetup_delete_event(self, *args):
        """done, quit the application"""
        #save settings
        self.save_setups()
        #save default window size & pos
        win_size = self.winSetup.get_size()
        self.wahcade_ini.set('setup_window_size', '%sx%s' % (win_size))
        self.wahcade_ini.write()
        #exit gtk loop
        gtk.main_quit()
        return False

    def on_Setup_changed(self, widget, *args):
        """widget has been modified, update altered flag"""
        self.setup_altered = True

    def on_mnuFSave_activate(self, *args):
        """save settings"""
        self.save_setups(False)

    def on_mnuFReset_activate(self, *args):
        """reset settings"""
        dlg = gtk.MessageDialog(
            self.winSetup,
            gtk.DIALOG_MODAL,
            gtk.MESSAGE_QUESTION,
            gtk.BUTTONS_YES_NO,
            _('Are you sure you want to revert to the default settings?'))
        resp = dlg.run()
        if resp == gtk.RESPONSE_YES:
            #delete and recreate settings dir
            shutil.rmtree(self.config_dir, True)
            self.copy_user_config('all')
            #reload settings
            self.load_settings()
            self.setup_altered = False
        dlg.destroy()

    def on_mnuFResetFilters_activate(self, *args):
        """reset file filters"""
        dlg = gtk.MessageDialog(
            self.winSetup,
            gtk.DIALOG_MODAL,
            gtk.MESSAGE_QUESTION,
            gtk.BUTTONS_YES_NO,
            _('Are you sure you want to reset the file filters?'))
        resp = dlg.run()
        if resp == gtk.RESPONSE_YES:
            #delete the ~/.wahcade/files dir
            shutil.rmtree(os.path.join(self.config_dir, 'files'), True)
            self.copy_user_config()
            #reload settings
            #self.load_settings()
            #self.setup_altered = False
        dlg.destroy()

    def on_mnuFQuit_activate(self, *args):
        """quit"""
        self.on_winSetup_delete_event()

    def on_mnuHAbout_activate(self, *args):
        """about dialog"""
        self.show_about_dialog('Wah!Cade Setup', self.config_dir)

    def on_tvwKeys_row_activated(self, widget, path, column):
        """keys list double-clicked"""
        #show key press dialog
        dlg = DlgKeyPress(
            SETUP_GLADE_FILE,
            'dlgKeyPress',
            path,
            self.on_tvwKeys_change,
            self.joystick)

    def on_tvwKeys_change(self, path, mw_keys, keyname):
        """update key list with new keyname"""
        #print "on_tvwKeys_change=",path, mw_keys, keyname
        #clear
        if mw_keys == [] and keyname == '':
            self.ctrlr_ini.set(self.lsKeys[path][0], '')
            self.lsKeys[path][1] = ''
            return
        #get existing actions for key
        mw_functions = self.ctrlr_ini.reverse_get(mw_keys[0])
        if mw_functions != []:
            #re-assign?
            key_actions = ''
            for f in mw_functions:
                key_actions += '\t%s\n' % f
            msg = _('"%s" is already assigned to the following actions:\n%s\n' % (
                keyname.upper(),
                key_actions))
            msg += _('Keep existing assignments?')
            dlg = gtk.MessageDialog(
                self.winSetup,
                gtk.DIALOG_MODAL,
                gtk.MESSAGE_QUESTION,
                gtk.BUTTONS_YES_NO,
                msg)
            resp = dlg.run()
            dlg.destroy()
            if resp == gtk.RESPONSE_NO:
                #remove from each old assignment
                for mrf in mw_functions:
                    v = self.ctrlr_ini.get(mrf)
                    lv = v.strip(' "').split(' | ')
                    lv.remove(mw_keys[0])
                    s = ''
                    for v in lv:
                        s = '%s | ' % v
                    if lv != []:
                        s = '"%s"' % s[:-3]
                    self.ctrlr_ini.set(mrf, s)
        #update keys for selected action
        existing_keys = self.ctrlr_ini.get(self.lsKeys[path][0])
        if existing_keys == '':
            self.ctrlr_ini.set(self.lsKeys[path][0], '"%s"' % mw_keys[0])
        else:
            self.ctrlr_ini.set(
                self.lsKeys[path][0],
                '"%s | %s"' % (existing_keys.strip('"'), mw_keys[0]))
        self.setup_altered = True
        #redisplay list
        self.populate_keys()

    def on_cboEmu_changed(self, *args):
        """emulator combo"""
        #save current emulator settings?
        if self.current_emu:
            self.save_emulator_settings()
            if self.current_emu_list:
                #save emu list settings
                self.save_emulator_list_settings()
                self.current_emu_list = None
        #change to new emulator
        if self.cboEmu.get_active() >= 0:
            self.current_emu = self.emu_lists[self.cboEmu.get_active()]
            self.load_emulator_settings(self.current_emu[1], self.current_emu[2])

    def on_txeEmuTitle_changed(self, widget, *args):
        """emu title changed"""
        #get aletered text
        new_title = widget.get_text()
        #get combo box postion
        idx = self.cboEmu.get_active()
        #has title changed?
        if new_title != self.emu_lists[idx][0] and new_title != '':
            #update emulators combo box
            self.emu_lists[idx][0] = new_title
            mdl = self.cboEmu.get_model()
            mdl[idx][0] = new_title
            self.setup_altered = True

    def on_cboEmuLists_changed(self, *args):
        """emulator list combo"""
        if self.current_emu_list:
            #save emu list settings
            self.save_emulator_list_settings()
        #get settings for current emu list
        idx = self.cboEmuLists.get_active()
        self.current_emu_list = self.emu_game_lists[idx]
        if idx >= 0:
            self.load_emulator_list_settings(idx, self.current_emu_list[1])

    def on_txeEmuListTitle_changed(self, widget, *args):
        """list title changed"""
        #get aletered text
        new_title = widget.get_text()
        #get combo box postion
        idx = self.cboEmuLists.get_active()
        #has title changed?
        if new_title != self.emu_game_lists[idx][0] and new_title != '':
            #update emulator lists combo box
            self.emu_game_lists[idx][0] = new_title
            mdl = self.cboEmuLists.get_model()
            mdl[idx][0] = '%s: %s' % (idx, new_title)
            self.setup_altered = True

    def on_btnWCOpenLayoutDir_clicked(self, widget, *args):
        """open layout dir"""
        self.open_dir_dialog(
            self.get_path(os.path.join(
                self.config_dir, 'layouts', self.txeWCLayoutDir.get_text())),
            'Set Layout Directory',
            self.set_layout_dir)

    def on_btnWCMovieIntroOpen_clicked(self, widget, *args):
        """intro movie file"""
        self.open_file_dialog(
            self.txeWCMovieIntro.get_text(),
            _('Set Intro Movie'),
            self.txeWCMovieIntro.set_text)

    def on_btnWCMovieExitOpen_clicked(self, widget, *args):
        """exit movie file"""
        self.open_file_dialog(
            self.txeWCMovieExit.get_text(),
            _('Set Exit Movie'),
            self.txeWCMovieExit.set_text)

    def on_btnWCOpenMusicDir_clicked(self, widget, *args):
        """open music dir"""
        self.open_dir_dialog(
            self.get_path(self.txeWCMusicDir.get_text()),
            'Set Music Directory',
            self.txeWCMusicDir.set_text)

    def on_btnEmuAdd_clicked(self, *args):
        """add new set of emulator files"""
        dlg = DlgAddEmu(SETUP_GLADE_FILE, 'dlgAddEmu', self)

    def on_btnEmuRemove_clicked(self, *args):
        """delete current set of emulator files"""
        #are you sure?
        dlg = gtk.MessageDialog(
            self.winSetup,
            gtk.DIALOG_MODAL,
            gtk.MESSAGE_QUESTION,
            gtk.BUTTONS_YES_NO,
            _('Are you sure you delete this Emulator (%s)?' % (self.current_emu[0])))
        resp = dlg.run()
        if resp == gtk.RESPONSE_YES:
            #go delete stuff
            emu_ini_name = self.current_emu[1]
            #remove emulator files (.fav, -nn.ftr, -nn.lst)
            self.remove_filespec('files', '%s.fav*' % emu_ini_name)
            self.remove_filespec('files', '%s-*.ftr' % emu_ini_name)
            self.remove_filespec('files', '%s-*.lst' % emu_ini_name)
            #remove ini files
            self.remove_filespec('ini', '%s-*.ini' % emu_ini_name)
            self.remove_filespec('ini', '%s.ini' % emu_ini_name)
            #reload settings
            self.load_settings()
            self.setup_altered = False
        dlg.destroy()

    def on_btnEmuListNew_clicked(self, *args):
        """add new emulator list files"""
        next_emu_list_num = len(self.cboEmuLists.get_model())
        emu_ini_name = self.current_emu[1]
        #copy template to ini dir
        shutil.copy2(
            os.path.join(APP_PATH, 'templates', 'default-1.ini'),
            os.path.join(self.config_dir, 'ini', '%s-%s.ini' % (emu_ini_name, next_emu_list_num)))
        #save & then reload
        self.save_emulator_list_settings()
        self.current_emu_list = None
        self.load_emulator_settings(self.current_emu[1], self.current_emu[2], next_emu_list_num)

    def on_btnEmuListDelete_clicked(self, *args):
        """delete current emulators list files"""
        #are you sure?
        dlg = gtk.MessageDialog(
            self.winSetup,
            gtk.DIALOG_MODAL,
            gtk.MESSAGE_QUESTION,
            gtk.BUTTONS_YES_NO,
            _('Are you sure you want to delete this List (%s)?' % (self.current_emu_list[0])))
        resp = dlg.run()
        if resp == gtk.RESPONSE_YES:
            #go delete stuff
            emu_ini_name = self.current_emu[1]
            emu_list_idx = self.cboEmuLists.get_active()
            self.remove_filespec('files', '%s-%s.ftr' % (emu_ini_name, emu_list_idx))
            self.remove_filespec('files', '%s-%s.lst' % (emu_ini_name, emu_list_idx))
            #remove ini files
            self.remove_filespec('ini', '%s-%s.ini' % (emu_ini_name, emu_list_idx))
            #renumber lists
            check_num = 1
            while check_num < MAX_LISTS:
                #find next missing file
                curr_ini = os.path.join(self.config_dir, 'ini', '%s-%s.ini' % (emu_ini_name, check_num))
                next_ini = os.path.join(self.config_dir, 'ini', '%s-%s.ini' % (emu_ini_name, (check_num + 1)))
                if not os.path.isfile(curr_ini) and  os.path.isfile(next_ini):
                    #rename next to current
                    os.rename(next_ini, curr_ini)
                    #rename list & filter files too
                    curr_ftr = os.path.join(self.config_dir, 'files', '%s-%s.ftr' % (emu_ini_name, check_num))
                    curr_lst = os.path.join(self.config_dir, 'files', '%s-%s.lst' % (emu_ini_name, check_num))
                    next_ftr = os.path.join(self.config_dir, 'files', '%s-%s.ftr' % (emu_ini_name, (check_num + 1)))
                    next_lst = os.path.join(self.config_dir, 'files', '%s-%s.lst' % (emu_ini_name, (check_num + 1)))
                    if os.path.isfile(curr_ftr):
                        os.remove(curr_ftr)
                    if os.path.isfile(curr_lst):
                        os.remove(curr_lst)
                    if os.path.isfile(next_ftr):
                        os.rename(next_ftr, curr_ftr)
                    if os.path.isfile(next_lst):
                        os.rename(next_lst, curr_lst)
                else:
                    #check next
                    check_num += 1
            #load emu list 0
            self.current_emu_list = 0
            self.load_emulator_settings(self.current_emu[1], self.current_emu[2])
        dlg.destroy()

    def on_btnEmuListFilter_clicked(self, *args):
        """set filter for list"""
        #idx = self.cboEmuLists.get_active()
        self.save_setups(False)
        self.WinFilter = WinFilter(SETUP_GLADE_FILE, 'winFilter', self.current_emu[1])#, idx)

    def on_btnEmuListEdit_clicked(self, *args):
        """edit the game list"""
        self.save_setups()
        self.WinList = WinList(
            SETUP_GLADE_FILE,
            'winList',
            self.current_emu[1],
            self.cboEmuLists.get_active())

    def on_btnEmuExeOpen_clicked(self, widget, *args):
        """emu executable"""
        self.open_file_dialog(
            self.get_path(self.txeEmuExe.get_text()),
            _('Set Emulator Executable'),
            self.txeEmuExe.set_text)

    def on_btnEmuRomDir_clicked(self, widget, *args):
        """emu rom dir"""
        self.open_dir_dialog(
            self.txeEmuRomDir.get_text(),
            _('Set Rom Directory'),
            self.txeEmuRomDir.set_text)

    def on_btnEmuNMSOpen_clicked(self, widget, *args):
        """nms file"""
        self.open_file_dialog(
            self.get_path(self.txeEmuNMSFile.get_text()),
            _('Set NMS File'),
            self.txeEmuNMSFile.set_text)

    def on_btnEmuScrMovieDir_clicked(self, widget, *args):
        """emu screen saver movie dir"""
        self.open_dir_dialog(
            self.txeEmuScrMovieDir.get_text(),
            _('Set Screen Saver Movie Directory'),
            self.txeEmuScrMovieDir.set_text)

    def on_btnEmuScrExternal_clicked(self, widget, *args):
        """emu external screen saver"""
        self.open_file_dialog(
            self.txeEmuScrExternal.get_text(),
            _('Set External Screen Saver'),
            self.txeEmuScrExternal.set_text)

    def on_btnEmuArt_clicked(self, widget, *args):
        """set emulator artwork dir"""
        idx = self.emu_artwork_btn.index(widget)
        self.open_dir_dialog(
            self.get_path(self.emu_artwork_txe[idx].get_text()),
            _('Set Artwork #%s Directory') % (idx + 1),
            self.emu_artwork_txe[idx].set_text)

    def on_btnEmuMovieDir_clicked(self, widget, *args):
        """emu movie dir"""
        self.open_dir_dialog(
            self.txeEmuMovieDir.get_text(),
            _('Set Movie Directory'),
            self.txeEmuMovieDir.set_text)

    def on_btnEmuExtApp_clicked(self, widget, *args):
        """set emu external app"""
        if widget == self.btnEmuExtApp1:
            txe = self.cboeEmuExtApp1.child
        elif widget == self.btnEmuExtApp2:
            txe = self.cboeEmuExtApp2.child
        else:
            txe = self.cboeEmuExtApp3.child
        self.open_file_dialog(
            self.get_path(self.txeMameXMLFile.get_text()),
            _('Set External Application'),
            txe.set_text)

    def on_btnMameXMLFile_clicked(self, widget, *args):
        """set mame xml info file"""
        self.open_file_dialog(
            self.get_path(self.txeMameXMLFile.get_text()),
            _('Set Mame XML / Data File'),
            self.txeMameXMLFile.set_text)

    def on_btnMameCatver_clicked(self, widget, *args):
        """set mame xml catver.ini file"""
        self.open_file_dialog(
            self.get_path(self.txeMameCatver.get_text()),
            _('Set Mame Category Version File'),
            self.txeMameCatver.set_text)

    def on_btnHstDatFile_clicked(self, widget, *args):
        """set history viewer history.dat file"""
        self.open_file_dialog(
            self.get_path(self.txeHstDatFile.get_text()),
            _('Set History Viewer history.dat File'),
            self.txeHstDatFile.set_text)

    def on_btnHstLayout_clicked(self, widget, *args):
        """set mame history viewer layout file"""
        self.open_file_dialog(
            self.get_path(self.txeHstLayout.get_text()),
            _('Set History Viewer Layout File'),
            self.txeHstLayout.set_text)

    def on_btnCPVIni_clicked(self, widget, *args):
        """set mame control panel viewer controls.ini file"""
        self.open_file_dialog(
            self.get_path(self.txeCPVIni.get_text()),
            _('Set Control Panel Viewer controls.ini File'),
            self.txeCPVIni.set_text)

    def on_btnCPVLayout_clicked(self, widget, *args):
        """set mame control panel viewer layout file"""
        self.open_file_dialog(
            self.get_path(self.txeCPVLayout.get_text()),
            _('Set Control Panel Viewer Layout File'),
            self.txeCPVLayout.set_text)

    def on_btnMameXMLGen_clicked(self, widget, *args):
        """generate mame xml info file"""
        #make sure mame emu is selected
        if self.current_emu[1] not in MAME_INI_FILES:
            self.show_msg_dialog(msg=_('Please select MAME Emulator first'))
            self.nbk.set_current_page(2)
            return
        #check mame exe exists
        if not os.path.isfile(self.txeEmuExe.get_text()):
            self.show_msg_dialog(msg=_('Please select valid MAME Application first'))
            self.nbk.set_current_page(2)
            return
        #default xml filename
        if self.txeMameXMLFile.get_text() == '' or not os.access(self.txeMameXMLFile.get_text(), os.W_OK):
            self.txeMameXMLFile.set_text(
                os.path.join(self.config_dir, 'files', 'mameinfo.xml'))
        #display wait dialog
        self.DlgWait = DlgWait(SETUP_GLADE_FILE, 'dlgWait', _('Please Wait. Creating XML File...'))
        #generate xml file
        if sys.platform != 'win32':
            redirect = ' 2>/dev/null'
        else:
            redirect = ''
        cmd = '%s -listxml > %s%s' % (
            self.txeEmuExe.get_text(),
            self.txeMameXMLFile.get_text(),
            redirect)
        #run emulator & wait for it to finish
        self.listxml_pid = Popen(cmd, shell=True)
        self.listxml_timer = gobject.timeout_add(500, self.wait_for_mame_listxml)

    def set_layout_dir(self, new_dir):
        """set layout directory"""
        self.txeWCLayoutDir.set_text(os.path.basename(new_dir))

    def wait_for_mame_listxml(self):
        """wait for listxml process to finish"""
        ret = self.listxml_pid.poll()
        if ret is not None:
            #finished - close wait dialog
            self.DlgWait.dlgWait.destroy()
            return False
        else:
            #still running...
            self.DlgWait.pgbWait.pulse()
            self.do_events()
            return True

    def save_setups(self, show_dialog=True):
        """save setup, prompt if show_dialog == True"""
        if self.setup_altered:
            ok_to_save = True
            if show_dialog:
                dlg = gtk.MessageDialog(
                    self.winSetup,
                    gtk.DIALOG_MODAL,
                    gtk.MESSAGE_QUESTION,
                    gtk.BUTTONS_YES_NO,
                    _('Save changes?'))
                resp = dlg.run()
                if resp != gtk.RESPONSE_YES:
                    ok_to_save = False
                dlg.destroy()
            #save?
            if ok_to_save:
                self.save_emulator_list_settings()
                self.save_emulator_settings()
                self.save_wahcade_settings()
                self.setup_altered = False

    def load_settings(self, default_emu=None):
        """load wahcade settings"""
        #build list of emulators
        self.emu_lists = self.buildemulist()
        self.current_emu = None
        self.current_emu_list = None
        #load emu combo
        l = ['%s (%s.ini)' % (e[0], e[1]) for e in self.emu_lists]
        self.setup_combo_box(self.cboEmu, l)
        #wahcade
        self.txeWCLayoutDir.set_text(self.wahcade_ini.get('layout'))
        self.chkWCFullscreen.set_active((self.wahcade_ini.getint('fullscreen', 0) == 1))
        self.spnWCScrDelay.set_value(self.wahcade_ini.getint('delay'))
        self.spnWCScrSlide.set_value(self.wahcade_ini.getint('slide_duration'))
        self.spnWCMovieDelay.set_value(self.wahcade_ini.getint('delay_before_movie_preview'))
        self.hscWCMovieVolume.set_value(self.wahcade_ini.getint('movie_volume'))
        ini_mix = self.wahcade_ini.get('music_movie_mix')
        mix_idx = [idx for idx, r in enumerate(self.music_movie_mix) if r[0] == ini_mix][0]
        self.cboWCMovieMix.set_active(mix_idx)
        self.txeWCMovieIntro.set_text(self.wahcade_ini.get('intro_movie_file'))
        self.txeWCMovieExit.set_text(self.wahcade_ini.get('exit_movie_file'))
        self.txeWCMusicDir.set_text(self.wahcade_ini.get('music_path'))
        self.chkWCMusic.set_active((self.wahcade_ini.getint('enable_music', 0) == 1))
        self.hscWCMusicVolume.set_value(self.wahcade_ini.getint('music_volume'))
        self.chkWCMusicShuffle.set_active((self.wahcade_ini.getint('shuffle_music', 0) == 1))
        self.chkWCMouseCursor.set_active((self.wahcade_ini.getint('show_cursor') == 1))
        self.chkWCWrapLists.set_active((self.wahcade_ini.getint('wrap_list') == 1))
        self.chkWCScaleImages.set_active((self.wahcade_ini.getint('keep_image_aspect') == 1))
        self.chkWCListArrows.set_active((self.wahcade_ini.getint('show_list_arrows', 0) == 1))
        #set emu
        set_idx = 0
        if default_emu:
            set_idx = [idx for idx, e in enumerate(self.emu_lists) if e[1] == default_emu][0]
        self.cboEmu.set_active(set_idx)
        #mame history viewer
        self.txeHstDatFile.set_text(self.histview_ini.get('history_dat_file'))
        self.txeHstLayout.set_text(self.histview_ini.get('history_layout'))
        #mame cp viewer
        self.txeCPVIni.set_text(self.cpviewer_ini.get('controls_ini_file'))
        self.txeCPVLayout.set_text(self.cpviewer_ini.get('viewer_layout'))
        #load keys
        self.chkKeysUseKeyboard.set_active((self.ctrlr_ini.getint('keyboard') == 1))
        self.chkKeysUseMouse.set_active((self.ctrlr_ini.getint('mouse') == 1))
        self.chkKeysUseJoystick.set_active((self.ctrlr_ini.getint('joystick') == 1))
        self.populate_keys()

    def load_emulator_settings(self, ini_name, emu_ini, default_list=0):
        """load emu settings"""
        
        # Default For Screens
        self.txeMameXMLFile.set_sensitive(True)
        self.btnMameXMLFile.set_sensitive(True)
        self.btnMameXMLGen.set_sensitive(True)
        self.btnEmuListFilter.set_sensitive(True)
        
        self.txeEmuTitle.set_text(emu_ini.get('emulator_title'))
        self.txeEmuExe.set_text(emu_ini.get('emulator_executable'))
        self.txeEmuCmdLine.set_text(emu_ini.get('commandline_format'))
        self.txeEmuAltCmdLine1.set_text(emu_ini.get('alt_commandline_format_1'))
        self.txeEmuAltCmdLine2.set_text(emu_ini.get('alt_commandline_format_2'))
        self.txeEmuRomExt.set_text(emu_ini.get('rom_extension'))
        self.txeEmuRomDir.set_text(emu_ini.get('rom_path'))
        self.txeEmuNMSFile.set_text(emu_ini.get('nms_file'))
        #list gen type
        ini_lgen = emu_ini.get('list_generation_method')
        lgen_idx = [idx for idx, r in enumerate(self.emu_list_gen_types) if ini_lgen in r[0]][0]
        self.cboEmuListGen.set_active(lgen_idx)
        #artwork
        for idx, emu_art in enumerate(self.emu_artwork_txe):
            emu_art.set_text(emu_ini.get('artwork_%s_image_path' % (idx + 1)))
        self.txeEmuMovieDir.set_text(emu_ini.get('movie_preview_path'))
        self.spnEmuMovieNum.set_value(emu_ini.getint('movie_artwork_no'))
        self.cboeEmuExtApp1.child.set_text(emu_ini.get('app_1_executable'))
        self.txeEmuExtApp1.set_text(emu_ini.get('app_1_commandline_format'))
        self.cboeEmuExtApp2.child.set_text(emu_ini.get('app_2_executable'))
        self.txeEmuExtApp2.set_text(emu_ini.get('app_2_commandline_format'))
        self.cboeEmuExtApp3.child.set_text(emu_ini.get('app_3_executable'))
        self.txeEmuExtApp3.set_text(emu_ini.get('app_3_commandline_format'))
        self.txeEmuExtAuto.set_text(emu_ini.get('auto_launch_apps'))
        #screen saver
        ini_scr = emu_ini.get('saver_type')
        scr_idx = [idx for idx, r in enumerate(self.emu_scrsave_types) if r[0] == ini_scr][0]
        self.cboEmuScrSaver.set_active(scr_idx)
        self.txeEmuScrMovieDir.set_text(emu_ini.get('movie_path'))
        self.txeEmuScrExternal.set_text(emu_ini.get('scr_file'))
        #load lists
        self.emu_game_lists = []
        ini_files = self.build_filelist("", "ini", "(?<=-)\d+", ini_name, "-")
        for ini_file in ini_files:
            if os.path.isfile(ini_file):
                list_ini = MameWahIni(ini_file)
                self.emu_game_lists.append([list_ini.get('list_title'), list_ini])
        l = ['%s: %s' % (i, r[0]) for i, r in enumerate(self.emu_game_lists)]
        self.setup_combo_box(self.cboEmuLists, l)
        self.cboEmuLists.set_active(default_list)

        self.txeMameXMLFile.set_text(emu_ini.get('dat_file'))
        self.txeMameCatver.set_text(emu_ini.get('catver_ini_file'))

        #mame only
        if not ini_name in MAME_INI_FILES:
            self.txeMameXMLFile.set_sensitive(False)
            self.btnMameXMLFile.set_sensitive(False)
            self.btnMameXMLGen.set_sensitive(False)
        
        if emu_ini.get('catver_ini_file') == "":
            self.btnEmuListFilter.set_sensitive(False)

    def load_emulator_list_settings(self, emu_list_idx, emu_list_ini):
        """load emulator list"""
        self.txeEmuListTitle.set_text(emu_list_ini.get('list_title'))
        #default or user-def list
        if emu_list_idx >= 1:
            #user defined list
            list_type = emu_list_ini.get('list_type')
            type_idx = [i for i, r in enumerate(self.emu_list_types) if r[0] == list_type][0]
            self.cboEmuListType.set_sensitive(True)
            self.btnEmuListDelete.set_sensitive(True)
        else:
            #default list
            type_idx = -1
            self.cboEmuListType.set_sensitive(False)
            self.btnEmuListDelete.set_sensitive(False)
        #set list type
        self.cboEmuListType.set_active(type_idx)
        self.chkEmuListCycle.set_active(emu_list_ini.getint('cycle_list') == 1)
        self.txeELCmdLine.set_text(emu_list_ini.get('commandline_format'))
        self.txeELAltCmdLine1.set_text(emu_list_ini.get('alt_commandline_format_1'))
        self.txeELAltCmdLine2.set_text(emu_list_ini.get('alt_commandline_format_2'))

    def save_wahcade_settings(self):
        """save wahcade settings"""
        #shift focus in order for spinner controls to update
        self.txeWCLayoutDir.grab_focus()
        #wahcade
        self.wahcade_ini.set('layout', self.txeWCLayoutDir.get_text())
        self.wahcade_ini.set('fullscreen', int(self.chkWCFullscreen.get_active()))
        self.wahcade_ini.set('delay', int(self.spnWCScrDelay.get_value()))
        self.wahcade_ini.set('slide_duration', int(self.spnWCScrSlide.get_value()))
        self.wahcade_ini.set('delay_before_movie_preview', int(self.spnWCMovieDelay.get_value()))
        self.wahcade_ini.set('movie_volume', int(self.hscWCMovieVolume.get_value()))
        self.wahcade_ini.set('music_movie_mix', self.music_movie_mix[self.cboWCMovieMix.get_active()][0])
        self.wahcade_ini.set('intro_movie_file', self.txeWCMovieIntro.get_text())
        self.wahcade_ini.set('exit_movie_file', self.txeWCMovieExit.get_text())
        self.wahcade_ini.set('music_path', self.txeWCMusicDir.get_text())
        self.wahcade_ini.set('enable_music', int(self.chkWCMusic.get_active()))
        self.wahcade_ini.set('music_volume', int(self.hscWCMusicVolume.get_value()))
        self.wahcade_ini.set('shuffle_music', int(self.chkWCMusicShuffle.get_active()))
        self.wahcade_ini.set('show_cursor', int(self.chkWCMouseCursor.get_active()))
        self.wahcade_ini.set('wrap_list', int(self.chkWCWrapLists.get_active()))
        self.wahcade_ini.set('keep_image_aspect', int(self.chkWCScaleImages.get_active()))
        self.wahcade_ini.set('show_list_arrows', int(self.chkWCListArrows.get_active()))
        #save ini
        self.wahcade_ini.write()
        #save controller settings
        #self.ctrlr_ini.set('keyboard', int(self.chkKeysUseKeyboard.get_active()))
        self.ctrlr_ini.set('mouse', int(self.chkKeysUseMouse.get_active()))
        self.ctrlr_ini.set('joystick', int(self.chkKeysUseJoystick.get_active()))
        self.ctrlr_ini.write()

    def save_emulator_settings(self):
        """save current emulator settings"""
        ini_name = self.current_emu[1]
        emu_ini = self.current_emu[2]
        emu_ini.set('emulator_title', self.txeEmuTitle.get_text())
        emu_ini.set('emulator_executable', self.txeEmuExe.get_text())
        emu_ini.set('commandline_format', self.txeEmuCmdLine.get_text())
        emu_ini.set('alt_commandline_format_1', self.txeEmuAltCmdLine1.get_text())
        emu_ini.set('alt_commandline_format_2', self.txeEmuAltCmdLine2.get_text())
        if self.txeEmuRomExt.get_text().startswith('.'):
            self.txeEmuRomExt.set_text(self.txeEmuRomExt.get_text()[1:])
        emu_ini.set('rom_extension', self.txeEmuRomExt.get_text())
        emu_ini.set('rom_path', self.txeEmuRomDir.get_text())
        emu_ini.set('nms_file', self.txeEmuNMSFile.get_text())
        emu_ini.set('list_generation_method', self.emu_list_gen_types[self.cboEmuListGen.get_active()][0][0])
        for idx, emu_art in enumerate(self.emu_artwork_txe):
            emu_ini.set('artwork_%s_image_path' % (idx + 1), emu_art.get_text())
        emu_ini.set('movie_preview_path', self.txeEmuMovieDir.get_text())
        emu_ini.set('movie_artwork_no', int(self.spnEmuMovieNum.get_value()))
        emu_ini.set('app_1_executable', self.cboeEmuExtApp1.child.get_text())
        emu_ini.set('app_1_commandline_format', self.txeEmuExtApp1.get_text())
        emu_ini.set('app_2_executable', self.cboeEmuExtApp2.child.get_text())
        emu_ini.set('app_2_commandline_format', self.txeEmuExtApp2.get_text())
        emu_ini.set('app_3_executable', self.cboeEmuExtApp3.child.get_text())
        emu_ini.set('app_3_commandline_format', self.txeEmuExtApp3.get_text())
        emu_ini.set('auto_launch_apps', self.txeEmuExtAuto.get_text())
        emu_ini.set('saver_type', self.emu_scrsave_types[self.cboEmuScrSaver.get_active()][0])
        emu_ini.set('movie_path', self.txeEmuScrMovieDir.get_text())
        emu_ini.set('scr_file', self.txeEmuScrExternal.get_text())
        emu_ini.set('catver_ini_file', self.txeMameCatver.get_text())
        #mame only
        if ini_name in MAME_INI_FILES:
            emu_ini.set('dat_file', self.txeMameXMLFile.get_text())
            #mame history viewer
            self.histview_ini.set('history_dat_file', self.txeHstDatFile.get_text())
            self.histview_ini.set('history_layout', self.txeHstLayout.get_text())
            #mame cp viewer
            self.cpviewer_ini.set('controls_ini_file', self.txeCPVIni.get_text())
            self.cpviewer_ini.set('viewer_layout', self.txeCPVLayout.get_text())
            #save
            self.histview_ini.write()
            self.cpviewer_ini.write()
        #save emu in ifiles
        emu_ini.write()

    def save_emulator_list_settings(self):
        """save emulator game list"""
        emu_list_ini = self.current_emu_list[1]
        emu_list_ini.set('list_title', self.txeEmuListTitle.get_text())
        if self.emu_game_lists.index(self.current_emu_list) >= 1:
            list_type = self.emu_list_types[self.cboEmuListType.get_active()][0]
            emu_list_ini.set('list_type', list_type)
        emu_list_ini.set('cycle_list', int(self.chkEmuListCycle.get_active()))
        emu_list_ini.set('commandline_format', self.txeELCmdLine.get_text())
        emu_list_ini.set('alt_commandline_format_1', self.txeELAltCmdLine1.get_text())
        emu_list_ini.set('alt_commandline_format_2', self.txeELAltCmdLine2.get_text())
        #save
        emu_list_ini.write()

    def create_new_emulator_files(self, template_ini_name, dest_ini_name):
        """create a new set of emulator files"""
        #copy template files to ini dir
        shutil.copy2(
            os.path.join(APP_PATH, 'templates', '%s.ini' % template_ini_name),
            os.path.join(self.config_dir, 'ini', '%s.ini' % dest_ini_name))
        shutil.copy2(
            os.path.join(APP_PATH, 'templates', 'default-0.ini'),
            os.path.join(self.config_dir, 'ini', '%s-0.ini' % dest_ini_name))
        #save & then reload
        self.on_mnuFSave_activate()
        self.load_settings(default_emu = dest_ini_name)

    def populate_keys(self):
        """pop keys list"""
        self.lsKeys.clear()
        #for each
        for ck, cv in self.ctrlr_ini.ini_dict.items():
            cv = str(cv)
            lv = cv.strip(' "').split(' | ')
            kb_vals = [v for v in lv if v.startswith('DIK_')]
            mouse_vals = [v for v in lv if v.startswith('MOUSE_')]
            joy_vals = [v for v in lv if v.startswith('JOY')]
            key_desc = ''
            #get key descriptions
            for keyval in kb_vals:
                keyname = [k for k, v in mamewah_keys.items() if keyval in v]
                if keyname != []:
                    if key_desc != '':
                        key_desc = '%s or %s' % (key_desc, keyname[0].upper())
                    else:
                        key_desc = '%s' % (keyname[0].upper())
            #get mouse descriptions
            for mouseval in mouse_vals:
                mousename = [k for k, v in _mouse_ctrls.items() if mouseval in v]
                if mousename != []:
                    if key_desc != '':
                        key_desc = '%s or %s' % (key_desc, mousename[0].upper())
                    else:
                        key_desc = '%s' % (mousename[0].upper())
            #get joystick descriptions
            for joyval in joy_vals:
                joyname = [k for k, v in self.joystick.ctrls.items() if joyval in v]
                if joyname != []:
                    if key_desc != '':
                        key_desc = '%s or %s' % (key_desc, joyname[0].upper())
                    else:
                        key_desc = '%s' % (joyname[0].upper())
            if ck.isupper():
                self.lsKeys.append((ck, key_desc))

    def open_file_dialog(self, default_filename, dlg_title, load_function):
        """open file dialog"""
        dlg = gtk.FileChooserDialog(
            title = dlg_title,
            action = gtk.FILE_CHOOSER_ACTION_OPEN,
            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        ftr = gtk.FileFilter()
        ftr.set_name("All files (*.*)")
        ftr.add_pattern("*")
        dlg.add_filter(ftr)
        dlg.set_filter(ftr)
        ftr = gtk.FileFilter()
        ftr.set_name("Config files (*.ini)")
        ftr.add_pattern("*.ini")
        dlg.add_filter(ftr)
        ftr = gtk.FileFilter()
        ftr.set_name("XML files (*.xml)")
        ftr.add_pattern("*.xml")
        dlg.add_filter(ftr)
        ftr = gtk.FileFilter()
        ftr.set_name("Dat files (*.dat)")
        ftr.add_pattern("*.dat")
        dlg.add_filter(ftr)
        if os.path.exists(default_filename):
            dlg.set_filename(default_filename)
        else:
            #dlg.set_current_folder(self.config_dir)
            dlg.set_current_folder(os.path.expanduser('~/'))
        response = dlg.run()
        if response == gtk.RESPONSE_OK:
            load_function(dlg.get_filename())
        dlg.destroy()

    def open_dir_dialog(self, default_dir, dlg_title, dlg_cb):
        """choose directory dialog"""
        dlg = gtk.FileChooserDialog(
            title = dlg_title,
            action = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        if os.path.exists(default_dir):
            dlg.set_filename(default_dir)
        else:
            dlg.set_current_folder(os.path.expanduser('~/'))
        response = dlg.run()
        if response == gtk.RESPONSE_OK:
            dlg_cb(dlg.get_filename())
        dlg.destroy()

    def save_layout_dialog(self, default_filename, dlg_title, save_function):
        """save file as... dialog"""
        dlg = gtk.FileChooserDialog(
            title = dlg_title,
            action = gtk.FILE_CHOOSER_ACTION_SAVE,
            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK))
        ftr = gtk.FileFilter()
        ftr.set_name("All files")
        ftr.add_pattern("*")
        dlg.add_filter(ftr)
        ftr = gtk.FileFilter()
        ftr.set_name("Ini files")
        ftr.add_pattern("*.ini")
        dlg.add_filter(ftr)
        dlg.set_filter(ftr)
        if gtk.check_version(2, 8, 0) is None:
            try:
                dlg.set_do_overwrite_confirmation(True)
            except AttributeError:
                pass
        dlg.set_filename(default_filename)
        response = dlg.run()
        if response == gtk.RESPONSE_OK:
            save_function(dlg.get_filename())
        dlg.destroy()

    def remove_filespec(self, *filespec):
        """delete files with given filespec"""
        files = glob.glob(os.path.join(self.config_dir, *filespec))
        [os.remove(f) for f in files]
Ejemplo n.º 4
0
class WinSetup(GladeSupport, WahCade):
    """wahcade setup - main window"""

    def __init__(self, glade_filename, window_name, config_opts, config_args):
        """build the window"""
        WahCade.__init__(self)
        GladeSupport.__init__(self, glade_filename, window_name, APP_NAME)
        #command-line options
        self.config_opts = config_opts
        #set default config location (create / update as necessary)
        self.config_dir = CONFIG_DIR
        if not os.path.exists(self.config_dir):
            self.copy_user_config('all')
        else:
            #update current config
            self.copy_user_config()
        #keys list
        self.tvwKeys, self.lsKeys, self.tvwsKeys = self.setup_treeview(
            columns = ['Function', 'Key'],
            column_types = [gobject.TYPE_STRING, gobject.TYPE_STRING],
            container = self.scwKeys,
            resizeable_cols = False)
        self.lsKeys.set_sort_column_id(0, gtk.SORT_ASCENDING)
        self.tvwKeys.connect('row-activated', self.on_tvwKeys_row_activated)
        self.tvwKeys.set_tooltip_text(_('Double-Click a row to change a Key...'))
        #set max width for keys column (stops window getting too wide)
        col = self.tvwKeys.get_column(1)
        col.set_max_width(200)
        #get ini files
        self.wahcade_ini = MameWahIni(os.path.join(self.config_dir, 'wahcade.ini'))
        self.histview_ini = MameWahIni(os.path.join(self.config_dir, 'histview.ini'))
        self.cpviewer_ini = MameWahIni(os.path.join(self.config_dir, 'cpviewer.ini'))
        self.ctrlr_ini = MameWahIni(os.path.join(self.config_dir, 'ctrlr', 'default.ini'), 'ctrlr')
        #emu stuff
        self.emu_list_gen_types = [
            [['rom_folder'], 'Rom Directory'],
            [['rom_folder_vs_listxml', 'list_xml'], 'XML File'],
            [['rom_folder_vs_dat_file', 'dat_file'], 'DAT File']]
        self.emu_scrsave_types = [
            ['blank_screen', 'Blank Screen'],
            ['slideshow', 'Slide Show'],
            ['movie', 'Movies'],
            ['launch_scr', 'Launch External Screen Saver']]
        self.emu_list_types = [
            ['normal', 'Normal'],
            ['most_played', 'Most Played'],
            ['longest_played', 'Longest Played'],
            ['hi2text_supported', 'High Score Supported'],
            ['xml_remote', 'XML Remote']]
        self.music_movie_mix = [
            ['mute_movies', 'Mute Movies'],
            ['merge', 'Mix with Music']]
        self.emu_artwork_txe = [
            self.txeEmuArt1, self.txeEmuArt2, self.txeEmuArt3, self.txeEmuArt4,
            self.txeEmuArt5, self.txeEmuArt6, self.txeEmuArt7, self.txeEmuArt8,
            self.txeEmuArt9, self.txeEmuArt10]
        self.emu_artwork_btn = [
            self.btnEmuArt1, self.btnEmuArt2, self.btnEmuArt3, self.btnEmuArt4,
            self.btnEmuArt5, self.btnEmuArt6, self.btnEmuArt7, self.btnEmuArt8,
            self.btnEmuArt9, self.btnEmuArt10]
        #setup combo boxes
        self.setup_combo_box(self.cboEmuScrSaver, [r[1] for r in self.emu_scrsave_types])
        self.setup_combo_box(self.cboEmuListGen, [r[1] for r in self.emu_list_gen_types])
        self.setup_combo_box(self.cboEmuListType, [r[1] for r in self.emu_list_types])
        self.setup_combo_box(self.cboWCMovieMix, [r[1] for r in self.music_movie_mix])
        #global joy
        self.joystick = joystick.joystick()
        self.joystick.use_all_controls()
        #get default window size & pos
        self.do_events()
        w, h = self.wahcade_ini.get('setup_window_size', 'default', '400x400').split('x')
        self.winSetup.resize(width=int(w), height=int(h))
        #load settings
        self.load_settings()
        self.setup_altered = False
        #set icon sizes
        settings = gtk.settings_get_default()
        settings.set_string_property('gtk-icon-sizes', 'gtk-button=16,16', '')

    def on_winSetup_delete_event(self, *args):
        """done, quit the application"""
        #save settings
        self.save_setups()
        #save default window size & pos
        win_size = self.winSetup.get_size()
        self.wahcade_ini.set('setup_window_size', '%sx%s' % (win_size))
        self.wahcade_ini.write()
        #exit gtk loop
        gtk.main_quit()
        return False

    def on_Setup_changed(self, widget, *args):
        """widget has been modified, update altered flag"""
        self.setup_altered = True

    def on_mnuFSave_activate(self, *args):
        """save settings"""
        self.save_setups(False)

    def on_mnuFReset_activate(self, *args):
        """reset settings"""
        dlg = gtk.MessageDialog(
            self.winSetup,
            gtk.DIALOG_MODAL,
            gtk.MESSAGE_QUESTION,
            gtk.BUTTONS_YES_NO,
            _('Are you sure you want to revert to the default settings?'))
        resp = dlg.run()
        if resp == gtk.RESPONSE_YES:
            #delete and recreate settings dir
            shutil.rmtree(self.config_dir, True)
            self.copy_user_config('all')
            #reload settings
            self.load_settings()
            self.setup_altered = False
        dlg.destroy()

    def on_mnuFResetFilters_activate(self, *args):
        """reset file filters"""
        dlg = gtk.MessageDialog(
            self.winSetup,
            gtk.DIALOG_MODAL,
            gtk.MESSAGE_QUESTION,
            gtk.BUTTONS_YES_NO,
            _('Are you sure you want to reset the file filters?'))
        resp = dlg.run()
        if resp == gtk.RESPONSE_YES:
            #delete the ~/.wahcade/files dir
            shutil.rmtree(os.path.join(self.config_dir, 'files'), True)
            self.copy_user_config()
            #reload settings
            #self.load_settings()
            #self.setup_altered = False
        dlg.destroy()

    def on_mnuFQuit_activate(self, *args):
        """quit"""
        self.on_winSetup_delete_event()

    def on_mnuHAbout_activate(self, *args):
        """about dialog"""
        self.show_about_dialog('Rcade Setup', self.config_dir)

    def on_tvwKeys_row_activated(self, widget, path, column):
        """keys list double-clicked"""
        #show key press dialog
        dlg = DlgKeyPress(
            SETUP_GLADE_FILE,
            'dlgKeyPress',
            path,
            self.on_tvwKeys_change,
            self.joystick)

    def on_tvwKeys_change(self, path, mw_keys, keyname):
        """update key list with new keyname"""
        #print "on_tvwKeys_change=",path, mw_keys, keyname
        #clear
        if mw_keys == [] and keyname == '':
            self.ctrlr_ini.set(self.lsKeys[path][0], '')
            self.lsKeys[path][1] = ''
            return
        #get existing actions for key
        mw_functions = self.ctrlr_ini.reverse_get(mw_keys[0])
        if mw_functions != []:
            #re-assign?
            key_actions = ''
            for f in mw_functions:
                key_actions += '\t%s\n' % f
            msg = _('"%s" is already assigned to the following actions:\n%s\n' % (
                keyname.upper(),
                key_actions))
            msg += _('Keep existing assignments?')
            dlg = gtk.MessageDialog(
                self.winSetup,
                gtk.DIALOG_MODAL,
                gtk.MESSAGE_QUESTION,
                gtk.BUTTONS_YES_NO,
                msg)
            resp = dlg.run()
            dlg.destroy()
            if resp == gtk.RESPONSE_NO:
                #remove from each old assignment
                for mrf in mw_functions:
                    v = self.ctrlr_ini.get(mrf)
                    lv = v.strip(' "').split(' | ')
                    lv.remove(mw_keys[0])
                    s = ''
                    for v in lv:
                        s = '%s | ' % v
                    if lv != []:
                        s = '"%s"' % s[:-3]
                    self.ctrlr_ini.set(mrf, s)
        #update keys for selected action
        existing_keys = self.ctrlr_ini.get(self.lsKeys[path][0])
        if existing_keys == '':
            self.ctrlr_ini.set(self.lsKeys[path][0], '"%s"' % mw_keys[0])
        else:
            self.ctrlr_ini.set(
                self.lsKeys[path][0],
                '"%s | %s"' % (existing_keys.strip('"'), mw_keys[0]))
        self.setup_altered = True
        #redisplay list
        self.populate_keys()

    def on_cboEmu_changed(self, *args):
        """emulator combo"""
        #save current emulator settings?
        if self.current_emu:
            self.save_emulator_settings()
            if self.current_emu_list:
                #save emu list settings
                self.save_emulator_list_settings()
                self.current_emu_list = None
        #change to new emulator
        if self.cboEmu.get_active() >= 0:
            self.current_emu = self.emu_lists[self.cboEmu.get_active()]
            self.load_emulator_settings(self.current_emu[1], self.current_emu[2])

    def on_txeEmuTitle_changed(self, widget, *args):
        """emu title changed"""
        #get aletered text
        new_title = widget.get_text()
        #get combo box postion
        idx = self.cboEmu.get_active()
        #has title changed?
        if new_title != self.emu_lists[idx][0] and new_title != '':
            #update emulators combo box
            self.emu_lists[idx][0] = new_title
            mdl = self.cboEmu.get_model()
            mdl[idx][0] = new_title
            self.setup_altered = True

    def on_cboEmuLists_changed(self, *args):
        """emulator list combo"""
        if self.current_emu_list:
            #save emu list settings
            self.save_emulator_list_settings()
        #get settings for current emu list
        idx = self.cboEmuLists.get_active()
        self.current_emu_list = self.emu_game_lists[idx]
        if idx >= 0:
            self.load_emulator_list_settings(idx, self.current_emu_list[1])

    def on_txeEmuListTitle_changed(self, widget, *args):
        """list title changed"""
        #get aletered text
        new_title = widget.get_text()
        #get combo box postion
        idx = self.cboEmuLists.get_active()
        #has title changed?
        if new_title != self.emu_game_lists[idx][0] and new_title != '':
            #update emulator lists combo box
            self.emu_game_lists[idx][0] = new_title
            mdl = self.cboEmuLists.get_model()
            mdl[idx][0] = '%s: %s' % (idx, new_title)
            self.setup_altered = True

    def on_btnWCOpenLayoutDir_clicked(self, widget, *args):
        """open layout dir"""
        self.open_dir_dialog(
            self.get_path(os.path.join(
                self.config_dir, 'layouts', self.txeWCLayoutDir.get_text())),
            'Set Layout Directory',
            self.set_layout_dir)

    def on_btnWCMovieIntroOpen_clicked(self, widget, *args):
        """intro movie file"""
        self.open_file_dialog(
            self.txeWCMovieIntro.get_text(),
            _('Set Intro Movie'),
            self.txeWCMovieIntro.set_text)

    def on_btnWCMovieExitOpen_clicked(self, widget, *args):
        """exit movie file"""
        self.open_file_dialog(
            self.txeWCMovieExit.get_text(),
            _('Set Exit Movie'),
            self.txeWCMovieExit.set_text)

    def on_btnWCOpenMusicDir_clicked(self, widget, *args):
        """open music dir"""
        self.open_dir_dialog(
            self.get_path(self.txeWCMusicDir.get_text()),
            'Set Music Directory',
            self.txeWCMusicDir.set_text)

    def on_btnEmuAdd_clicked(self, *args):
        """add new set of emulator files"""
        dlg = DlgAddEmu(SETUP_GLADE_FILE, 'dlgAddEmu', self)

    def on_btnEmuRemove_clicked(self, *args):
        """delete current set of emulator files"""
        #are you sure?
        dlg = gtk.MessageDialog(
            self.winSetup,
            gtk.DIALOG_MODAL,
            gtk.MESSAGE_QUESTION,
            gtk.BUTTONS_YES_NO,
            _('Are you sure you delete this Emulator (%s)?' % (self.current_emu[0])))
        resp = dlg.run()
        if resp == gtk.RESPONSE_YES:
            #go delete stuff
            emu_ini_name = self.current_emu[1]
            #remove emulator files (.fav, -nn.ftr, -nn.lst)
            self.remove_filespec('files', '%s.fav*' % emu_ini_name)
            self.remove_filespec('files', '%s-*.ftr' % emu_ini_name)
            self.remove_filespec('files', '%s-*.lst' % emu_ini_name)
            #remove ini files
            self.remove_filespec('ini', '%s-*.ini' % emu_ini_name)
            self.remove_filespec('ini', '%s.ini' % emu_ini_name)
            #reload settings
            self.load_settings()
            self.setup_altered = False
        dlg.destroy()

    def on_btnEmuListNew_clicked(self, *args):
        """add new emulator list files"""
        next_emu_list_num = len(self.cboEmuLists.get_model())
        emu_ini_name = self.current_emu[1]
        #copy template to ini dir
        shutil.copy2(
            os.path.join(APP_PATH, 'templates', 'default-1.ini'),
            os.path.join(self.config_dir, 'ini', '%s-%s.ini' % (emu_ini_name, next_emu_list_num)))
        #save & then reload
        self.save_emulator_list_settings()
        self.current_emu_list = None
        self.load_emulator_settings(self.current_emu[1], self.current_emu[2], next_emu_list_num)

    def on_btnEmuListDelete_clicked(self, *args):
        """delete current emulators list files"""
        #are you sure?
        dlg = gtk.MessageDialog(
            self.winSetup,
            gtk.DIALOG_MODAL,
            gtk.MESSAGE_QUESTION,
            gtk.BUTTONS_YES_NO,
            _('Are you sure you want to delete this List (%s)?' % (self.current_emu_list[0])))
        resp = dlg.run()
        if resp == gtk.RESPONSE_YES:
            #go delete stuff
            emu_ini_name = self.current_emu[1]
            emu_list_idx = self.cboEmuLists.get_active()
            self.remove_filespec('files', '%s-%s.ftr' % (emu_ini_name, emu_list_idx))
            self.remove_filespec('files', '%s-%s.lst' % (emu_ini_name, emu_list_idx))
            #remove ini files
            self.remove_filespec('ini', '%s-%s.ini' % (emu_ini_name, emu_list_idx))
            #renumber lists
            check_num = 1
            while check_num < MAX_LISTS:
                #find next missing file
                curr_ini = os.path.join(self.config_dir, 'ini', '%s-%s.ini' % (emu_ini_name, check_num))
                next_ini = os.path.join(self.config_dir, 'ini', '%s-%s.ini' % (emu_ini_name, (check_num + 1)))
                if not os.path.isfile(curr_ini) and  os.path.isfile(next_ini):
                    #rename next to current
                    os.rename(next_ini, curr_ini)
                    #rename list & filter files too
                    curr_ftr = os.path.join(self.config_dir, 'files', '%s-%s.ftr' % (emu_ini_name, check_num))
                    curr_lst = os.path.join(self.config_dir, 'files', '%s-%s.lst' % (emu_ini_name, check_num))
                    next_ftr = os.path.join(self.config_dir, 'files', '%s-%s.ftr' % (emu_ini_name, (check_num + 1)))
                    next_lst = os.path.join(self.config_dir, 'files', '%s-%s.lst' % (emu_ini_name, (check_num + 1)))
                    if os.path.isfile(curr_ftr):
                        os.remove(curr_ftr)
                    if os.path.isfile(curr_lst):
                        os.remove(curr_lst)
                    if os.path.isfile(next_ftr):
                        os.rename(next_ftr, curr_ftr)
                    if os.path.isfile(next_lst):
                        os.rename(next_lst, curr_lst)
                else:
                    #check next
                    check_num += 1
            #load emu list 0
            self.current_emu_list = 0
            self.load_emulator_settings(self.current_emu[1], self.current_emu[2])
        dlg.destroy()

    def on_btnEmuListFilter_clicked(self, *args):
        """set filter for list"""
        #idx = self.cboEmuLists.get_active()
        self.save_setups(False)
        self.WinFilter = WinFilter(SETUP_GLADE_FILE, 'winFilter', self.current_emu[1])#, idx)

    def on_btnEmuListEdit_clicked(self, *args):
        """edit the game list"""
        self.save_setups()
        self.WinList = WinList(
            SETUP_GLADE_FILE,
            'winList',
            self.current_emu[1],
            self.cboEmuLists.get_active())

    def on_btnEmuExeOpen_clicked(self, widget, *args):
        """emu executable"""
        self.open_file_dialog(
            self.get_path(self.txeEmuExe.get_text()),
            _('Set Emulator Executable'),
            self.txeEmuExe.set_text)

    def on_btnEmuRomDir_clicked(self, widget, *args):
        """emu rom dir"""
        self.open_dir_dialog(
            self.txeEmuRomDir.get_text(),
            _('Set Rom Directory'),
            self.txeEmuRomDir.set_text)

    def on_btnEmuNMSOpen_clicked(self, widget, *args):
        """nms file"""
        self.open_file_dialog(
            self.get_path(self.txeEmuNMSFile.get_text()),
            _('Set NMS File'),
            self.txeEmuNMSFile.set_text)

    def on_btnEmuScrMovieDir_clicked(self, widget, *args):
        """emu screen saver movie dir"""
        self.open_dir_dialog(
            self.txeEmuScrMovieDir.get_text(),
            _('Set Screen Saver Movie Directory'),
            self.txeEmuScrMovieDir.set_text)

    def on_btnEmuScrExternal_clicked(self, widget, *args):
        """emu external screen saver"""
        self.open_file_dialog(
            self.txeEmuScrExternal.get_text(),
            _('Set External Screen Saver'),
            self.txeEmuScrExternal.set_text)

    def on_btnEmuArt_clicked(self, widget, *args):
        """set emulator artwork dir"""
        idx = self.emu_artwork_btn.index(widget)
        self.open_dir_dialog(
            self.get_path(self.emu_artwork_txe[idx].get_text()),
            _('Set Artwork #%s Directory') % (idx + 1),
            self.emu_artwork_txe[idx].set_text)

    def on_btnEmuMovieDir_clicked(self, widget, *args):
        """emu movie dir"""
        self.open_dir_dialog(
            self.txeEmuMovieDir.get_text(),
            _('Set Movie Directory'),
            self.txeEmuMovieDir.set_text)

    def on_btnEmuExtApp_clicked(self, widget, *args):
        """set emu external app"""
        if widget == self.btnEmuExtApp1:
            txe = self.cboeEmuExtApp1.child
        elif widget == self.btnEmuExtApp2:
            txe = self.cboeEmuExtApp2.child
        else:
            txe = self.cboeEmuExtApp3.child
        self.open_file_dialog(
            self.get_path(self.txeMameXMLFile.get_text()),
            _('Set External Application'),
            txe.set_text)

    def on_btnMameXMLFile_clicked(self, widget, *args):
        """set mame xml info file"""
        self.open_file_dialog(
            self.get_path(self.txeMameXMLFile.get_text()),
            _('Set Mame XML / Data File'),
            self.txeMameXMLFile.set_text)

    def on_btnMameCatver_clicked(self, widget, *args):
        """set mame xml catver.ini file"""
        self.open_file_dialog(
            self.get_path(self.txeMameCatver.get_text()),
            _('Set Mame Category Version File'),
            self.txeMameCatver.set_text)

    def on_btnHstDatFile_clicked(self, widget, *args):
        """set history viewer history.dat file"""
        self.open_file_dialog(
            self.get_path(self.txeHstDatFile.get_text()),
            _('Set History Viewer history.dat File'),
            self.txeHstDatFile.set_text)

    def on_btnHstLayout_clicked(self, widget, *args):
        """set mame history viewer layout file"""
        self.open_file_dialog(
            self.get_path(self.txeHstLayout.get_text()),
            _('Set History Viewer Layout File'),
            self.txeHstLayout.set_text)

    def on_btnCPVIni_clicked(self, widget, *args):
        """set mame control panel viewer controls.ini file"""
        self.open_file_dialog(
            self.get_path(self.txeCPVIni.get_text()),
            _('Set Control Panel Viewer controls.ini File'),
            self.txeCPVIni.set_text)

    def on_btnCPVLayout_clicked(self, widget, *args):
        """set mame control panel viewer layout file"""
        self.open_file_dialog(
            self.get_path(self.txeCPVLayout.get_text()),
            _('Set Control Panel Viewer Layout File'),
            self.txeCPVLayout.set_text)

    def on_btnMameXMLGen_clicked(self, widget, *args):
        """generate mame xml info file"""
        #make sure mame emu is selected
        if self.current_emu[1] not in MAME_INI_FILES:
            self.show_msg_dialog(msg=_('Please select MAME Emulator first'))
            self.nbk.set_current_page(2)
            return
        #check mame exe exists
        if not os.path.isfile(self.txeEmuExe.get_text()):
            self.show_msg_dialog(msg=_('Please select valid MAME Application first'))
            self.nbk.set_current_page(2)
            return
        #default xml filename
        if self.txeMameXMLFile.get_text() == '' or not os.access(self.txeMameXMLFile.get_text(), os.W_OK):
            self.txeMameXMLFile.set_text(
                os.path.join(self.config_dir, 'files', 'mameinfo.xml'))
        #display wait dialog
        self.DlgWait = DlgWait(SETUP_GLADE_FILE, 'dlgWait', _('Please Wait. Creating XML File...'))
        #generate xml file
        if sys.platform != 'win32':
            redirect = ' 2>/dev/null'
        else:
            redirect = ''
        cmd = '%s -listxml > %s%s' % (
            self.txeEmuExe.get_text(),
            self.txeMameXMLFile.get_text(),
            redirect)
        #run emulator & wait for it to finish
        self.listxml_pid = Popen(cmd, shell=True)
        self.listxml_timer = gobject.timeout_add(500, self.wait_for_mame_listxml)

    def set_layout_dir(self, new_dir):
        """set layout directory"""
        self.txeWCLayoutDir.set_text(os.path.basename(new_dir))

    def wait_for_mame_listxml(self):
        """wait for listxml process to finish"""
        ret = self.listxml_pid.poll()
        if ret is not None:
            #finished - close wait dialog
            self.DlgWait.dlgWait.destroy()
            return False
        else:
            #still running...
            self.DlgWait.pgbWait.pulse()
            self.do_events()
            return True

    def save_setups(self, show_dialog=True):
        """save setup, prompt if show_dialog == True"""
        if self.setup_altered:
            ok_to_save = True
            if show_dialog:
                dlg = gtk.MessageDialog(
                    self.winSetup,
                    gtk.DIALOG_MODAL,
                    gtk.MESSAGE_QUESTION,
                    gtk.BUTTONS_YES_NO,
                    _('Save changes?'))
                resp = dlg.run()
                if resp != gtk.RESPONSE_YES:
                    ok_to_save = False
                dlg.destroy()
            #save?
            if ok_to_save:
                self.save_emulator_list_settings()
                self.save_emulator_settings()
                self.save_wahcade_settings()
                self.setup_altered = False

    def load_settings(self, default_emu=None):
        """load wahcade settings"""
        #build list of emulators
        self.emu_lists = self.buildemulist()
        self.current_emu = None
        self.current_emu_list = None
        #load emu combo
        l = ['%s (%s.ini)' % (e[0], e[1]) for e in self.emu_lists]
        self.setup_combo_box(self.cboEmu, l)
        #wahcade
        self.txeWCLayoutDir.set_text(self.wahcade_ini.get('layout'))
        self.chkWCFullscreen.set_active((self.wahcade_ini.getint('fullscreen', 0) == 1))
        self.spnWCScrDelay.set_value(self.wahcade_ini.getint('delay'))
        self.spnWCScrSlide.set_value(self.wahcade_ini.getint('slide_duration'))
        self.spnWCMovieDelay.set_value(self.wahcade_ini.getint('delay_before_movie_preview'))
        self.hscWCMovieVolume.set_value(self.wahcade_ini.getint('movie_volume'))
        ini_mix = self.wahcade_ini.get('music_movie_mix')
        mix_idx = [idx for idx, r in enumerate(self.music_movie_mix) if r[0] == ini_mix][0]
        self.cboWCMovieMix.set_active(mix_idx)
        self.txeWCMovieIntro.set_text(self.wahcade_ini.get('intro_movie_file'))
        self.txeWCMovieExit.set_text(self.wahcade_ini.get('exit_movie_file'))
        self.txeWCMusicDir.set_text(self.wahcade_ini.get('music_path'))
        self.chkWCMusic.set_active((self.wahcade_ini.getint('enable_music', 0) == 1))
        self.hscWCMusicVolume.set_value(self.wahcade_ini.getint('music_volume'))
        self.chkWCMusicShuffle.set_active((self.wahcade_ini.getint('shuffle_music', 0) == 1))
        self.chkWCMouseCursor.set_active((self.wahcade_ini.getint('show_cursor') == 1))
        self.chkWCWrapLists.set_active((self.wahcade_ini.getint('wrap_list') == 1))
        self.chkWCScaleImages.set_active((self.wahcade_ini.getint('keep_image_aspect') == 1))
        self.chkWCListArrows.set_active((self.wahcade_ini.getint('show_list_arrows', 0) == 1))
        #set emu
        set_idx = 0
        if default_emu:
            set_idx = [idx for idx, e in enumerate(self.emu_lists) if e[1] == default_emu][0]
        self.cboEmu.set_active(set_idx)
        #mame history viewer
        self.txeHstDatFile.set_text(self.histview_ini.get('history_dat_file'))
        self.txeHstLayout.set_text(self.histview_ini.get('history_layout'))
        #mame cp viewer
        self.txeCPVIni.set_text(self.cpviewer_ini.get('controls_ini_file'))
        self.txeCPVLayout.set_text(self.cpviewer_ini.get('viewer_layout'))
        #load keys
        self.chkKeysUseKeyboard.set_active((self.ctrlr_ini.getint('keyboard') == 1))
        self.chkKeysUseMouse.set_active((self.ctrlr_ini.getint('mouse') == 1))
        self.chkKeysUseJoystick.set_active((self.ctrlr_ini.getint('joystick') == 1))
        self.populate_keys()

    def load_emulator_settings(self, ini_name, emu_ini, default_list=0):
        """load emu settings"""
        
        # Default For Screens
        self.txeMameXMLFile.set_sensitive(True)
        self.btnMameXMLFile.set_sensitive(True)
        self.btnMameXMLGen.set_sensitive(True)
        self.btnEmuListFilter.set_sensitive(True)
        
        self.txeEmuTitle.set_text(emu_ini.get('emulator_title'))
        self.txeEmuExe.set_text(emu_ini.get('emulator_executable'))
        self.txeEmuCmdLine.set_text(emu_ini.get('commandline_format'))
        self.txeEmuAltCmdLine1.set_text(emu_ini.get('alt_commandline_format_1'))
        self.txeEmuAltCmdLine2.set_text(emu_ini.get('alt_commandline_format_2'))
        self.txeEmuRomExt.set_text(emu_ini.get('rom_extension'))
        self.txeEmuRomDir.set_text(emu_ini.get('rom_path'))
        self.txeEmuNMSFile.set_text(emu_ini.get('nms_file'))
        #list gen type
        ini_lgen = emu_ini.get('list_generation_method')
        lgen_idx = [idx for idx, r in enumerate(self.emu_list_gen_types) if ini_lgen in r[0]][0]
        self.cboEmuListGen.set_active(lgen_idx)
        #artwork
        for idx, emu_art in enumerate(self.emu_artwork_txe):
            emu_art.set_text(emu_ini.get('artwork_%s_image_path' % (idx + 1)))
        self.txeEmuMovieDir.set_text(emu_ini.get('movie_preview_path'))
        self.spnEmuMovieNum.set_value(emu_ini.getint('movie_artwork_no'))
        self.cboeEmuExtApp1.child.set_text(emu_ini.get('app_1_executable'))
        self.txeEmuExtApp1.set_text(emu_ini.get('app_1_commandline_format'))
        self.cboeEmuExtApp2.child.set_text(emu_ini.get('app_2_executable'))
        self.txeEmuExtApp2.set_text(emu_ini.get('app_2_commandline_format'))
        self.cboeEmuExtApp3.child.set_text(emu_ini.get('app_3_executable'))
        self.txeEmuExtApp3.set_text(emu_ini.get('app_3_commandline_format'))
        self.txeEmuExtAuto.set_text(emu_ini.get('auto_launch_apps'))
        #screen saver
        ini_scr = emu_ini.get('saver_type')
        scr_idx = [idx for idx, r in enumerate(self.emu_scrsave_types) if r[0] == ini_scr][0]
        self.cboEmuScrSaver.set_active(scr_idx)
        self.txeEmuScrMovieDir.set_text(emu_ini.get('movie_path'))
        self.txeEmuScrExternal.set_text(emu_ini.get('scr_file'))
        #load lists
        self.emu_game_lists = []
        ini_files = self.build_filelist("", "ini", "(?<=-)\d+", ini_name, "-")
        for ini_file in ini_files:
            if os.path.isfile(ini_file):
                list_ini = MameWahIni(ini_file)
                self.emu_game_lists.append([list_ini.get('list_title'), list_ini])
        l = ['%s: %s' % (i, r[0]) for i, r in enumerate(self.emu_game_lists)]
        self.setup_combo_box(self.cboEmuLists, l)
        self.cboEmuLists.set_active(default_list)

        self.txeMameXMLFile.set_text(emu_ini.get('dat_file'))
        self.txeMameCatver.set_text(emu_ini.get('catver_ini_file'))

        #mame only
        if not ini_name in MAME_INI_FILES:
            self.txeMameXMLFile.set_sensitive(False)
            self.btnMameXMLFile.set_sensitive(False)
            self.btnMameXMLGen.set_sensitive(False)
        
        if emu_ini.get('catver_ini_file') == "":
            self.btnEmuListFilter.set_sensitive(False)

    def load_emulator_list_settings(self, emu_list_idx, emu_list_ini):
        """load emulator list"""
        self.txeEmuListTitle.set_text(emu_list_ini.get('list_title'))
        #default or user-def list
        if emu_list_idx >= 1:
            #user defined list
            list_type = emu_list_ini.get('list_type')
            type_idx = [i for i, r in enumerate(self.emu_list_types) if r[0] == list_type][0]
            self.cboEmuListType.set_sensitive(True)
            self.btnEmuListDelete.set_sensitive(True)
        else:
            #default list
            type_idx = -1
            self.cboEmuListType.set_sensitive(False)
            self.btnEmuListDelete.set_sensitive(False)
        #set list type
        self.cboEmuListType.set_active(type_idx)
        self.chkEmuListCycle.set_active(emu_list_ini.getint('cycle_list') == 1)
        self.txeELCmdLine.set_text(emu_list_ini.get('commandline_format'))
        self.txeELAltCmdLine1.set_text(emu_list_ini.get('alt_commandline_format_1'))
        self.txeELAltCmdLine2.set_text(emu_list_ini.get('alt_commandline_format_2'))

    def save_wahcade_settings(self):
        """save wahcade settings"""
        #shift focus in order for spinner controls to update
        self.txeWCLayoutDir.grab_focus()
        #wahcade
        self.wahcade_ini.set('layout', self.txeWCLayoutDir.get_text())
        self.wahcade_ini.set('fullscreen', int(self.chkWCFullscreen.get_active()))
        self.wahcade_ini.set('delay', int(self.spnWCScrDelay.get_value()))
        self.wahcade_ini.set('slide_duration', int(self.spnWCScrSlide.get_value()))
        self.wahcade_ini.set('delay_before_movie_preview', int(self.spnWCMovieDelay.get_value()))
        self.wahcade_ini.set('movie_volume', int(self.hscWCMovieVolume.get_value()))
        self.wahcade_ini.set('music_movie_mix', self.music_movie_mix[self.cboWCMovieMix.get_active()][0])
        self.wahcade_ini.set('intro_movie_file', self.txeWCMovieIntro.get_text())
        self.wahcade_ini.set('exit_movie_file', self.txeWCMovieExit.get_text())
        self.wahcade_ini.set('music_path', self.txeWCMusicDir.get_text())
        self.wahcade_ini.set('enable_music', int(self.chkWCMusic.get_active()))
        self.wahcade_ini.set('music_volume', int(self.hscWCMusicVolume.get_value()))
        self.wahcade_ini.set('shuffle_music', int(self.chkWCMusicShuffle.get_active()))
        self.wahcade_ini.set('show_cursor', int(self.chkWCMouseCursor.get_active()))
        self.wahcade_ini.set('wrap_list', int(self.chkWCWrapLists.get_active()))
        self.wahcade_ini.set('keep_image_aspect', int(self.chkWCScaleImages.get_active()))
        self.wahcade_ini.set('show_list_arrows', int(self.chkWCListArrows.get_active()))
        #save ini
        self.wahcade_ini.write()
        #save controller settings
        #self.ctrlr_ini.set('keyboard', int(self.chkKeysUseKeyboard.get_active()))
        self.ctrlr_ini.set('mouse', int(self.chkKeysUseMouse.get_active()))
        self.ctrlr_ini.set('joystick', int(self.chkKeysUseJoystick.get_active()))
        self.ctrlr_ini.write()

    def save_emulator_settings(self):
        """save current emulator settings"""
        ini_name = self.current_emu[1]
        emu_ini = self.current_emu[2]
        emu_ini.set('emulator_title', self.txeEmuTitle.get_text())
        emu_ini.set('emulator_executable', self.txeEmuExe.get_text())
        emu_ini.set('commandline_format', self.txeEmuCmdLine.get_text())
        emu_ini.set('alt_commandline_format_1', self.txeEmuAltCmdLine1.get_text())
        emu_ini.set('alt_commandline_format_2', self.txeEmuAltCmdLine2.get_text())
        if self.txeEmuRomExt.get_text().startswith('.'):
            self.txeEmuRomExt.set_text(self.txeEmuRomExt.get_text()[1:])
        emu_ini.set('rom_extension', self.txeEmuRomExt.get_text())
        emu_ini.set('rom_path', self.txeEmuRomDir.get_text())
        emu_ini.set('nms_file', self.txeEmuNMSFile.get_text())
        emu_ini.set('list_generation_method', self.emu_list_gen_types[self.cboEmuListGen.get_active()][0][0])
        for idx, emu_art in enumerate(self.emu_artwork_txe):
            emu_ini.set('artwork_%s_image_path' % (idx + 1), emu_art.get_text())
        emu_ini.set('movie_preview_path', self.txeEmuMovieDir.get_text())
        emu_ini.set('movie_artwork_no', int(self.spnEmuMovieNum.get_value()))
        emu_ini.set('app_1_executable', self.cboeEmuExtApp1.child.get_text())
        emu_ini.set('app_1_commandline_format', self.txeEmuExtApp1.get_text())
        emu_ini.set('app_2_executable', self.cboeEmuExtApp2.child.get_text())
        emu_ini.set('app_2_commandline_format', self.txeEmuExtApp2.get_text())
        emu_ini.set('app_3_executable', self.cboeEmuExtApp3.child.get_text())
        emu_ini.set('app_3_commandline_format', self.txeEmuExtApp3.get_text())
        emu_ini.set('auto_launch_apps', self.txeEmuExtAuto.get_text())
        emu_ini.set('saver_type', self.emu_scrsave_types[self.cboEmuScrSaver.get_active()][0])
        emu_ini.set('movie_path', self.txeEmuScrMovieDir.get_text())
        emu_ini.set('scr_file', self.txeEmuScrExternal.get_text())
        emu_ini.set('catver_ini_file', self.txeMameCatver.get_text())
        #mame only
        if ini_name in MAME_INI_FILES:
            emu_ini.set('dat_file', self.txeMameXMLFile.get_text())
            #mame history viewer
            self.histview_ini.set('history_dat_file', self.txeHstDatFile.get_text())
            self.histview_ini.set('history_layout', self.txeHstLayout.get_text())
            #mame cp viewer
            self.cpviewer_ini.set('controls_ini_file', self.txeCPVIni.get_text())
            self.cpviewer_ini.set('viewer_layout', self.txeCPVLayout.get_text())
            #save
            self.histview_ini.write()
            self.cpviewer_ini.write()
        #save emu in ifiles
        emu_ini.write()

    def save_emulator_list_settings(self):
        """save emulator game list"""
        emu_list_ini = self.current_emu_list[1]
        emu_list_ini.set('list_title', self.txeEmuListTitle.get_text())
        if self.emu_game_lists.index(self.current_emu_list) >= 1:
            list_type = self.emu_list_types[self.cboEmuListType.get_active()][0]
            emu_list_ini.set('list_type', list_type)
            if list_type == "xml_remote":
                emu_list_ini.set('params', "")
        emu_list_ini.set('cycle_list', int(self.chkEmuListCycle.get_active()))
        emu_list_ini.set('commandline_format', self.txeELCmdLine.get_text())
        emu_list_ini.set('alt_commandline_format_1', self.txeELAltCmdLine1.get_text())
        emu_list_ini.set('alt_commandline_format_2', self.txeELAltCmdLine2.get_text())
        #save
        emu_list_ini.write()

    def create_new_emulator_files(self, template_ini_name, dest_ini_name):
        """create a new set of emulator files"""
        #copy template files to ini dir
        shutil.copy2(
            os.path.join(APP_PATH, 'templates', '%s.ini' % template_ini_name),
            os.path.join(self.config_dir, 'ini', '%s.ini' % dest_ini_name))
        shutil.copy2(
            os.path.join(APP_PATH, 'templates', 'default-0.ini'),
            os.path.join(self.config_dir, 'ini', '%s-0.ini' % dest_ini_name))
        #save & then reload
        self.on_mnuFSave_activate()
        self.load_settings(default_emu = dest_ini_name)

    def populate_keys(self):
        """pop keys list"""
        self.lsKeys.clear()
        #for each
        for ck, cv in self.ctrlr_ini.ini_dict.items():
            cv = str(cv)
            lv = cv.strip(' "').split(' | ')
            kb_vals = [v for v in lv if v.startswith('DIK_')]
            mouse_vals = [v for v in lv if v.startswith('MOUSE_')]
            joy_vals = [v for v in lv if v.startswith('JOY')]
            key_desc = ''
            #get key descriptions
            for keyval in kb_vals:
                keyname = [k for k, v in mamewah_keys.items() if keyval in v]
                if keyname != []:
                    if key_desc != '':
                        key_desc = '%s or %s' % (key_desc, keyname[0].upper())
                    else:
                        key_desc = '%s' % (keyname[0].upper())
            #get mouse descriptions
            for mouseval in mouse_vals:
                mousename = [k for k, v in _mouse_ctrls.items() if mouseval in v]
                if mousename != []:
                    if key_desc != '':
                        key_desc = '%s or %s' % (key_desc, mousename[0].upper())
                    else:
                        key_desc = '%s' % (mousename[0].upper())
            #get joystick descriptions
            for joyval in joy_vals:
                joyname = [k for k, v in self.joystick.ctrls.items() if joyval in v]
                if joyname != []:
                    if key_desc != '':
                        key_desc = '%s or %s' % (key_desc, joyname[0].upper())
                    else:
                        key_desc = '%s' % (joyname[0].upper())
            if ck.isupper():
                self.lsKeys.append((ck, key_desc))

    def open_file_dialog(self, default_filename, dlg_title, load_function):
        """open file dialog"""
        dlg = gtk.FileChooserDialog(
            title = dlg_title,
            action = gtk.FILE_CHOOSER_ACTION_OPEN,
            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        ftr = gtk.FileFilter()
        ftr.set_name("All files (*.*)")
        ftr.add_pattern("*")
        dlg.add_filter(ftr)
        dlg.set_filter(ftr)
        ftr = gtk.FileFilter()
        ftr.set_name("Config files (*.ini)")
        ftr.add_pattern("*.ini")
        dlg.add_filter(ftr)
        ftr = gtk.FileFilter()
        ftr.set_name("XML files (*.xml)")
        ftr.add_pattern("*.xml")
        dlg.add_filter(ftr)
        ftr = gtk.FileFilter()
        ftr.set_name("Dat files (*.dat)")
        ftr.add_pattern("*.dat")
        dlg.add_filter(ftr)
        if os.path.exists(default_filename):
            dlg.set_filename(default_filename)
        else:
            #dlg.set_current_folder(self.config_dir)
            dlg.set_current_folder(os.path.expanduser('~/'))
        response = dlg.run()
        if response == gtk.RESPONSE_OK:
            load_function(dlg.get_filename())
        dlg.destroy()

    def open_dir_dialog(self, default_dir, dlg_title, dlg_cb):
        """choose directory dialog"""
        dlg = gtk.FileChooserDialog(
            title = dlg_title,
            action = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        if os.path.exists(default_dir):
            dlg.set_filename(default_dir)
        else:
            dlg.set_current_folder(os.path.expanduser('~/'))
        response = dlg.run()
        if response == gtk.RESPONSE_OK:
            dlg_cb(dlg.get_filename())
        dlg.destroy()

    def save_layout_dialog(self, default_filename, dlg_title, save_function):
        """save file as... dialog"""
        dlg = gtk.FileChooserDialog(
            title = dlg_title,
            action = gtk.FILE_CHOOSER_ACTION_SAVE,
            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK))
        ftr = gtk.FileFilter()
        ftr.set_name("All files")
        ftr.add_pattern("*")
        dlg.add_filter(ftr)
        ftr = gtk.FileFilter()
        ftr.set_name("Ini files")
        ftr.add_pattern("*.ini")
        dlg.add_filter(ftr)
        dlg.set_filter(ftr)
        if gtk.check_version(2, 8, 0) is None:
            try:
                dlg.set_do_overwrite_confirmation(True)
            except AttributeError:
                pass
        dlg.set_filename(default_filename)
        response = dlg.run()
        if response == gtk.RESPONSE_OK:
            save_function(dlg.get_filename())
        dlg.destroy()

    def remove_filespec(self, *filespec):
        """delete files with given filespec"""
        files = glob.glob(os.path.join(self.config_dir, *filespec))
        [os.remove(f) for f in files]