Пример #1
0
def main(svc_input, configs):
    logger = Logger("查询日志", verbose=True)
    log_file_name = "log%s_%s.txt" % (svc_input.replace("?", "#"), DateTimeUtil.get_current_datetime(is_date=True))
    log_file_path = WindowsUtil.convert_win_path(os.path.join(temp_dir, log_file_name))
    logger.info("[开始查询] %s" % svc_input)
    try:
        # 找到本地匹配的保修历史记录
        history_zip = ZipFileSVC(zip_file_path=history_zipfile, mode='a')
        start_time = DateTimeUtil.get_current_datetime()
        # 创建出所有可能查询码
        svc_generator = SVCGenerator(svc_input, logger)
        logger.info("创建出所有可能查询码:%s" % len(svc_generator.target_svc_set))
        # 根据本地匹配的非法查询码历史,筛选出目标查询码,以及非法查询码
        existed_svc = history_zip.find_file_regex(svc_generator.regex)
        svc_generator.generate_target_svc_batch(existed_svc, invalid_history_file_path)
        # 调用戴尔查询API,并将API数据转化为实体类数据
        output_dell_asset_list = list([])
        if svc_generator.target_svc_set:
            batch = Batch(logger, configs)
            api_dell_asset_list = batch.begin(svc_generator.target_svc_set)
            output_dell_asset_list = api_dell_asset_list
            logger.info("从API中总共得到%s个结果" % (len(api_dell_asset_list)))
            logger.info("将实体类序列化到本地临时TXT文件")
            temp_text_files_path = DellAsset.serialize_txt_batch(api_dell_asset_list, temp_dir)
            logger.info("将序列化临时文件存到本地zip历史记录,总数:%s" % len(temp_text_files_path))
            history_zip.add_new_file_batch(temp_text_files_path)
            logger.info("删除临时 %s 个TXT文件" % len(temp_text_files_path))
            for file_path in temp_text_files_path:
                FileUtil.delete_file(file_path)
            logger.info("将API得到的实体类和历史记录实体类合并")
        else:
            logger.warn("目标查询码为空,仅从从历史记录中导出结果")
        for svc in svc_generator.existed_svc_set:
            dell_asset_content = history_zip.get_member_content(file_name="%s.txt" % svc)
            output_dell_asset_list.append(DellAsset.deserialize_txt(dell_asset_content))
        logger.info("添加历史记录,总共得到%s个结果" % (len(output_dell_asset_list)))
        excel_output_path = WindowsUtil.convert_win_path(os.path.join(excel_dir, "%s.xlsx" % svc_generator.get_file_name()))
        DellAsset.save_as_excel_batch(output_dell_asset_list, excel_output_path)
        if FileUtil.is_path_existed(excel_output_path):
            logger.info("存为Excel文档成功")
            end_time = DateTimeUtil.get_current_datetime()
            logger.info("总用时 %s " % DateTimeUtil.datetime_diff(start_time, end_time))
            logger.info("[查询结束] 总共%s个结果 保存在:%s" % (len(output_dell_asset_list), excel_output_path))
        else:
            logger.error("[保存结果失败] %s" % excel_output_path)
    except Exception as e:
        # 若程序出现错误失败,发送邮件
        logger.error("[查询失败] 已发送报告 请等待解决")
        logger.error("%s\n%s" % (e, traceback.format_exc()))
        logger.save(log_file_path)
        email_api_key = configs["email_api_key"]
        email = Email(email_api_key, subject="[查询失败] %s %s" % (DateTimeUtil.get_current_datetime(is_date=True), svc_input))
        email.add_attachment(log_file_path)
        email.send(cc_mode=logger.has_error)
Пример #2
0
def main(svc_input, configs):
    logger = Logger("查询日志", verbose=True)
    log_file_name = "log%s_%s.txt" % (svc_input.replace(
        "?", "#"), DateTimeUtil.get_current_datetime(is_date=True))
    log_file_path = WindowsUtil.convert_win_path(
        os.path.join(temp_dir, log_file_name))
    logger.info("[开始查询] %s" % svc_input)
    try:
        # 找到本地匹配的保修历史记录
        history_zip = ZipFileSVC(zip_file_path=history_zipfile, mode='a')
        start_time = DateTimeUtil.get_current_datetime()
        # 创建出所有可能查询码
        svc_generator = SVCGenerator(svc_input, logger)
        logger.info("创建出所有可能查询码:%s" % len(svc_generator.target_svc_set))
        # 根据本地匹配的非法查询码历史,筛选出目标查询码,以及非法查询码
        existed_svc = history_zip.find_file_regex(svc_generator.regex)
        svc_generator.generate_target_svc_batch(existed_svc,
                                                invalid_history_file_path)
        # 调用戴尔查询API,并将API数据转化为实体类数据
        output_dell_asset_list = list([])
        if svc_generator.target_svc_set:
            batch = Batch(logger, configs)
            api_dell_asset_list = batch.begin(svc_generator.target_svc_set)
            output_dell_asset_list = api_dell_asset_list
            logger.info("从API中总共得到%s个结果" % (len(api_dell_asset_list)))
            logger.info("将实体类序列化到本地临时TXT文件")
            temp_text_files_path = DellAsset.serialize_txt_batch(
                api_dell_asset_list, temp_dir)
            logger.info("将序列化临时文件存到本地zip历史记录,总数:%s" %
                        len(temp_text_files_path))
            history_zip.add_new_file_batch(temp_text_files_path)
            logger.info("删除临时 %s 个TXT文件" % len(temp_text_files_path))
            for file_path in temp_text_files_path:
                FileUtil.delete_file(file_path)
            logger.info("将API得到的实体类和历史记录实体类合并")
        else:
            logger.warn("目标查询码为空,仅从从历史记录中导出结果")
        for svc in svc_generator.existed_svc_set:
            dell_asset_content = history_zip.get_member_content(
                file_name="%s.txt" % svc)
            output_dell_asset_list.append(
                DellAsset.deserialize_txt(dell_asset_content))
        logger.info("添加历史记录,总共得到%s个结果" % (len(output_dell_asset_list)))
        excel_output_path = WindowsUtil.convert_win_path(
            os.path.join(excel_dir, "%s.xlsx" % svc_generator.get_file_name()))
        DellAsset.save_as_excel_batch(output_dell_asset_list,
                                      excel_output_path)
        if FileUtil.is_path_existed(excel_output_path):
            logger.info("存为Excel文档成功")
            end_time = DateTimeUtil.get_current_datetime()
            logger.info("总用时 %s " %
                        DateTimeUtil.datetime_diff(start_time, end_time))
            logger.info("[查询结束] 总共%s个结果 保存在:%s" %
                        (len(output_dell_asset_list), excel_output_path))
        else:
            logger.error("[保存结果失败] %s" % excel_output_path)
    except Exception as e:
        # 若程序出现错误失败,发送邮件
        logger.error("[查询失败] 已发送报告 请等待解决")
        logger.error("%s\n%s" % (e, traceback.format_exc()))
        logger.save(log_file_path)
        email_api_key = configs["email_api_key"]
        email = Email(
            email_api_key,
            subject="[查询失败] %s %s" %
            (DateTimeUtil.get_current_datetime(is_date=True), svc_input))
        email.add_attachment(log_file_path)
        email.send(cc_mode=logger.has_error)
Пример #3
0
class LineWidgit(tkinter.Frame):
    '''
    This is the GUI widget that represents a single line in the output
    data. It uses the data_store to communicate values into and out of
    itself.
    '''

    def __init__(self, parent,lineno):
        self.logger = Logger(self, Logger.INFO)
        self.logger.debug("constructor")
        tkinter.Frame.__init__(self, parent)

        self.data_store = DataStore.get_instance()
        self.index = lineno

        self.name = "Hole %d" % (lineno+1)
        self.line_name = tkinter.Label(self, text=self.name, width=12)
        self.line_name.grid(row=lineno+1, column=0, sticky=tkinter.W)

        self.inter_ctl = tkinter.Entry(self, width=5, validate="focusout", validatecommand=self.change_interval)
        self.inter_ctl.bind('<Return>', self.change_interval)
        self.inter_ctl.bind('<Tab>', self.change_interval)
        self.inter_ctl.grid(row=lineno+1, column=1)

        self.note_ctl_txt = tkinter.StringVar()
        self.note_ctl = tkinter.Label(self, textvariable=self.note_ctl_txt, width=12)
        self.note_ctl.grid(row=lineno+1, column=2)

        self.freq_ctl_txt = tkinter.StringVar()
        self.freq_ctl = tkinter.Label(self, textvariable=self.freq_ctl_txt, width=12)
        self.freq_ctl.grid(row=lineno+1, column=3)

        self.hole_ctl = HoleSizeWidgit(self, lineno)
        self.hole_ctl.config(padx=25)
        self.hole_ctl.grid(row=lineno+1, column=4)

        self.locat_ctl_txt = tkinter.StringVar()
        self.locat_ctl = tkinter.Label(self, textvariable=self.locat_ctl_txt, width=12)
        self.locat_ctl.grid(row=lineno+1, column=5)

        self.diff_ctl_txt = tkinter.StringVar()
        self.diff_ctl = tkinter.Label(self, textvariable=self.diff_ctl_txt, width=12)
        self.diff_ctl.grid(row=lineno+1, column=6)

        self.cutoff_ctl_txt = tkinter.StringVar()
        self.cutoff_ctl = tkinter.Label(self, textvariable=self.cutoff_ctl_txt, width=12)
        self.cutoff_ctl.grid(row=lineno+1, column=7)

        self.set_state()

        self.logger.debug("end constructor")

    @debugger
    def set_state(self):
        '''
        Place the data from the data_store into the GUI.
        '''
        self.inter_ctl.delete(0, tkinter.END)
        self.inter_ctl.insert(0, str(self.data_store.get_hole_interval(self.index)))
        self.note_ctl_txt.set(str(self.data_store.get_hole_note(self.index))) # Label
        self.freq_ctl_txt.set("%s Hz"%(str(self.data_store.get_hole_freq(self.index))))
        self.locat_ctl_txt.set("%0.4f"%self.data_store.get_hole_xloc(self.index)) # Label
        self.diff_ctl_txt.set("%0.4f"%self.data_store.get_hole_diff(self.index)) # Label
        self.cutoff_ctl_txt.set("%0.4f"%self.data_store.get_hole_cutoff(self.index)) # Label
        self.hole_ctl.set_state()

    @debugger
    def get_state(self):
        '''
        Get the data out of the display and place it in the data_store.
        '''
        self.data_store.set_hole_interval(self.index, int(self.inter_ctl.get()))
        self.data_store.set_hole_note(self.index, self.note_ctl_txt.get()) # str
        self.data_store.set_hole_freq(self.index, float(self.freq_ctl_txt.get().split()[0]))
        self.data_store.set_hole_location(self.index, float(self.locat_ctl_txt.get()))
        self.data_store.set_hole_diff(self.index, float(self.diff_ctl_txt.get()))
        self.data_store.set_hole_cutoff(self.index, float(self.cutoff_ctl_txt.get()))
        self.hole_ctl.get_state()

    @debugger
    def print_state(self):
        self.logger.msg(str(self.get_state()))

    @debugger
    def change_units(self):
        '''
        When this is called, it is assumed that the datastore and the GUI need to have
        the vaules updated to reflect the new units.
        '''
        if self.data_store.get_units():
            self.data_store.set_hole_size(self.index, utility.in_to_mm(self.data_store.get_hole_size(self.index)))
            self.data_store.set_hole_location(self.index, utility.in_to_mm(self.data_store.get_hole_location(self.index)))
            self.data_store.set_hole_diff(self.index, utility.in_to_mm(self.data_store.get_hole_diff(self.index)))
            self.data_store.set_hole_cutoff(self.index, utility.in_to_mm(self.data_store.get_hole_cutoff(self.index)))
        else:
            self.data_store.set_hole_size(self.index, utility.mm_to_in(self.data_store.get_hole_size(self.index)))
            self.data_store.set_hole_location(self.index, utility.mm_to_in(self.data_store.get_hole_location(self.index)))
            self.data_store.set_hole_diff(self.index, utility.mm_to_in(self.data_store.get_hole_diff(self.index)))
            self.data_store.set_hole_cutoff(self.index, utility.mm_to_in(self.data_store.get_hole_cutoff(self.index)))
        self.set_state()
        self.data_store.set_change_flag()

    @debugger
    def change_interval(self, event=None):
        try:
            val = int(self.inter_ctl.get())
            oldval = self.data_store.get_hole_interval(self.index)
            if val != oldval:
                if val > 0 and val < 5:
                    self.data_store.set_hole_interval(self.index, val)
                    self.logger.debug("change interval from %d to %d"%(oldval, val))
                    raise_event("UPDATE_NOTES_EVENT")
                    self.data_store.set_change_flag()
                else:
                    self.logger.error("invalid value for interval: %s"%(str(self.inter_ctl.get())))
                    messagebox.showerror("ERROR", "Intervals must be an integer between 1 and 4")
                    self.inter_ctl.delete(0, tkinter.END)
                    self.inter_ctl.insert(0, str(self.data_store.get_hole_interval(self.index)))
                    return False
            else:
                self.logger.debug("ignore")
        except ValueError:
            self.logger.error("invalid integer for interval: %s"%(str(self.inter_ctl.get())))
            messagebox.showerror("ERROR", "Cannot convert the string \"%s\" to an integer between 1 1nd 4"%(self.inter_ctl.get()))
            self.inter_ctl.delete(0, tkinter.END)
            self.inter_ctl.insert(0, str(self.data_store.get_hole_interval(self.index)))
            return False
        except IndexError:
            pass  # always ignore

        return True
Пример #4
0
class DependencyScriptConfiguration(object):
    @staticmethod
    def GetConfigurationFilename(scriptFilename):
        path, ext = os.path.splitext(argv[0])
        path, name = os.path.split(path)
        return '{0}.ini'.format(name)

    def __init__(self, argv=None, argparser=None):
        # Make an argparser if we were not given one already.
        if argparser is None:
            self.argparser = argparse.ArgumentParser(description='Generates an SQLite3 database containing all of the #include dependencies in your project.')
        else:
            self.argparser = argparser
        
        # Add our arguments to the argparser.
        self.argparser.add_argument('-C', '--print-example-config', action='store_true', default=False, dest='printExampleConfig', help='The script requires a configuration file in the current directory or the script directory in order to run. This option generates an example config file that lists all the available options. Note: the databases must have the same filename in the config file. You will also want to make sure that the default filename, :memory:, is no longer set. If it was then you won\'t have a file to work with. Read the comments in the example config for details.')
        self.argparser.add_argument('--debug', action='store_true', default=False, dest='debugMessages', help='Print the debug messages. Very verbose, use only in development.')
        self.argparser.add_argument('--verbose', action='store_true', default=False, dest='verbose', help='Print the info messages about progress and status.')
        self.argparser.add_argument('--silence-errors', action='store_true', default=False, dest='silenceErrors', help='Don\'t print any errors.')
        self.argparser.add_argument('-c', '--config-filename', dest='scriptIni', metavar='<config-filename>', help='Specifies the path to the configuration file to use.')
        self.argparser.add_argument('-f', '--database-filename', dest='databaseFilename', metavar='<db-filename>', help='Specifies the filename of the database. Note: specifying this option overrides the filename in the configuration file.')
        self.argparser.add_argument('-s', '--source-path', dest='sourcePath', metavar='<source-path>', help='Specifies the path to the root of the source code.')
        
        # Configure the rest of our class. We need to initialize unused variables if we want to use
        # them later in our class.
        if argv is not None:
            self.Configure(argv)
        else:
            self.ClearConfiguration()

    def Configure(self, argv):
        self.args = argv
        self.messagePrinter = Logger()
        
        self.scriptPath, self.scriptExtension = os.path.splitext(argv[0])
        self.scriptPath, self.scriptName = os.path.split(self.scriptPath)
        
        self.argparser.parse_args(args=argv[1:], namespace=self)
        
        self.messagePrinter.isDbgEnabled = self.debugMessages
        self.messagePrinter.isInfoEnabled = self.verbose
        self.messagePrinter.isErrEnabled = not self.silenceErrors
        
        if self.scriptIni is None:
            iniPath = ''
            if self.scriptPath is not None:
                iniPath = self.scriptPath
            self.scriptIni = toPosixPath(os.path.join(iniPath, '{0}.ini'.format(self.scriptName)))
        
        self.parser = configparser.ConfigParser(allow_no_value = True) # see https://docs.python.org/2/library/configparser.html
        self.parser.optionxform = str # make case-sensitive as per https://docs.python.org/2/library/configparser.html
        
        self.isConfigured = True
        
        if os.path.exists(self.scriptIni):
            self.parser.read(self.scriptIni)
        elif os.path.exists(os.path.join(self.scriptPath, self.scriptIni)):
            self.parser.read(os.path.join(self.scriptPath, self.scriptIni))
        else:
            msg = "No configuration file found. Searched, current directory and script directory directory for {0}.".format(self.scriptIni)
            self.messagePrinter.error(msg)
            self.isConfigured = False
            
            self.databaseFilename = ':memory:'
            self.sourcePath = './'
            return
        
        try:
            if self.databaseFilename is None:
                self.databaseFilename = self.parser.get("Output", "DatabaseFilename")
        except:
            self.databaseFilename = ':memory:'
        
        try:
            if self.sourcePath is None:
                self.sourcePath = self.parser.get("Paths","SourceRoot")
                # Make the read SourceRoot path relative to the INI file's path.
                if self.isConfigured:
                    iniPath, iniFilename = os.path.split(self.scriptIni)
                    self.sourcePath = toPosixPath(os.path.normpath(os.path.join(iniPath, self.sourcePath)))
                    print('source-path: {0}'.format(self.sourcePath))
        except:
            self.sourcePath = './'
        
    def ClearConfiguration(self):
        self.args = None
        self.parser = None
        self.scriptName = None
        self.scriptPath = None
        self.scriptExtension = None
        self.scriptIni = None
class UpperFrame(tkinter.Frame):
    '''
    This class manages the upper frame of the display.
    '''
    def __init__(self, master):
        self.logger = Logger(self, Logger.INFO)
        self.logger.debug("constructor")
        self.master = master
        self.data_store = DataStore.get_instance()
        register_event("UPDATE_UPPER_EVENT", self.set_state)

    @debugger
    def create_frame(self):
        # build the screen

        # Fill in the upper frame
        tkinter.Label(self.master, text="Title").grid(row=0, column=0, sticky=tkinter.E)
        self.titleEntry = tkinter.Entry(self.master, width=40, validate="focusout", validatecommand=self.setTitleCommand)
        self.titleEntry.bind('<Return>', self.setTitleCommand)
        self.titleEntry.bind('<Tab>', self.setTitleCommand)
        self.titleEntry.grid(row=0, column=1, columnspan=3, padx=9, pady=4)

        tkinter.Label(self.master, text="Inside Diameter").grid(row=1, column=0, sticky=tkinter.E, pady=4)
        self.insideDiaEntry = tkinter.Entry(self.master, validate="focusout", validatecommand=self.insideDiaCommand)
        self.insideDiaEntry.bind('<Return>', self.insideDiaCommand)
        self.insideDiaEntry.bind('<Tab>', self.insideDiaCommand)
        self.insideDiaEntry.grid(row=1, column=1, pady=4)

        tkinter.Label(self.master, text="Wall Thickness").grid(row=1, column=2, sticky=tkinter.E, pady=4)
        self.wallThicknessEntry = tkinter.Entry(self.master, validate="focusout", validatecommand=self.wallThicknessCommand)
        self.wallThicknessEntry.bind('<Return>', self.wallThicknessCommand)
        self.wallThicknessEntry.bind('<Tab>', self.wallThicknessCommand)
        self.wallThicknessEntry.grid(row=1, column=3, pady=4)

        tkinter.Label(self.master, text="Number of Holes").grid(row=2, column=0, sticky=tkinter.E, pady=4)
        self.numHolesEntry = tkinter.Entry(self.master, validate="focusout", validatecommand=self.numHolesCommand)
        self.numHolesEntry.bind('<Return>', self.numHolesCommand)
        self.numHolesEntry.bind('<Tab>', self.numHolesCommand)
        self.numHolesEntry.grid(row=2, column=1, pady=4)

        tkinter.Label(self.master, text="Select Bell Note").grid(row=2, column=2, sticky=tkinter.E, pady=4)
        self.bellNoteCombo = ttk.Combobox(self.master, state="readonly", values=self.data_store.bellNoteArray)
        self.bellNoteCombo.config(width=17)
        self.bellNoteCombo.grid(row=2, column=3, pady=4)
        self.bellNoteCombo.bind("<<ComboboxSelected>>", self.bellSelectCallback)

        tkinter.Label(self.master, text="Embouchure Area").grid(row=4, column=0, sticky=tkinter.E, pady=4)
        self.embouchureAreaEntry = tkinter.Entry(self.master)
        self.embouchureAreaEntry.grid(row=4, column=1, pady=4)

        tkinter.Label(self.master, text="Units of Measure").grid(row=3, column=0, sticky=tkinter.E, pady=4)
        self.measureUnitsOpt = ttk.Combobox(self.master, state="readonly", values=["inch", "mm"])
        self.measureUnitsOpt.config(width=17)
        self.measureUnitsOpt.grid(row=3, column=1, pady=4)
        self.measureUnitsOpt.bind("<<ComboboxSelected>>", self.measureUnitsCallback)

        tkinter.Label(self.master, text="Display Format").grid(row=3, column=2, sticky=tkinter.E, pady=4)
        self.displayFormatOpt = ttk.Combobox(self.master, state="readonly", values=["decimal", "fraction"])
        self.displayFormatOpt.current(1)
        self.displayFormatOpt.config(width=17)
        self.displayFormatOpt.grid(row=3, column=3, pady=4)
        self.displayFormatOpt.bind("<<ComboboxSelected>>", self.displayFormatCallback)

        tkinter.Label(self.master, text="Length").grid(row=4, column=2, sticky=tkinter.E, pady=4)
        self.lengthEntry = tkinter.Entry(self.master)
        self.lengthEntry.grid(row=4, column=3, pady=4)

        if self.measureUnitsOpt.get() == 'mm':
            self.displayFormatOpt.config(state="readonly")

        self.refreshButton = tkinter.Button(
            self.master, text="Refresh", width=14, command=self.refreshButtonCommand)
        self.refreshButton.grid(row=5, column=0, columnspan=4, pady=4)

        self.set_state() # write what's in the data_store to the GUI

    @debugger
    def get_state(self):
        '''
        Return the state of the controls in the upper half into the data store.
        '''

        if self.displayFormatOpt.current() == 0:
            self.data_store.set_disp_frac(False)
        else:
            self.data_store.set_disp_frac(True)

        if self.measureUnitsOpt.current() == 0:
            self.data_store.set_units(False)
        else:
            self.data_store.set_units(True)

        self.data_store.set_title(self.titleEntry.get())
        self.data_store.set_inside_dia(float(self.insideDiaEntry.get()))
        self.data_store.set_wall_thickness(float(self.wallThicknessEntry.get()))
        self.data_store.set_number_holes(int(self.numHolesEntry.get()))
        self.data_store.set_bell_note_select(self.bellNoteCombo.current())
        #self.data_store.set_embouchure_area(float(self.embouchureAreaEntry.get()))
        self.data_store.set_bell_freq(
            self.data_store.note_table[self.data_store.get_bell_note_select()]['frequency'])


    @debugger
    def set_state(self):
        '''
        Take the state from the data store and put in the GUI.
        '''
        self.titleEntry.delete(0, tkinter.END)
        self.titleEntry.insert(0, self.data_store.get_title())

        self.bellNoteCombo.current(self.data_store.get_bell_note_select())
        self.measureUnitsOpt.current(int(self.data_store.get_units())) # it's a bool in the data_store
        self.displayFormatOpt.current(int(self.data_store.get_disp_frac())) # it's a bool in the data_store

        self.insideDiaEntry.delete(0, tkinter.END)
        self.insideDiaEntry.insert(0, str(self.data_store.get_inside_dia()))

        self.wallThicknessEntry.delete(0, tkinter.END)
        self.wallThicknessEntry.insert(0, str(self.data_store.get_wall_thickness()))

        self.numHolesEntry.delete(0, tkinter.END)
        self.numHolesEntry.insert(0, str(self.data_store.get_number_holes()))

        self.embouchureAreaEntry.config(state=tkinter.NORMAL)
        self.embouchureAreaEntry.delete(0, tkinter.END)
        self.embouchureAreaEntry.insert(0, "%0.4f"%(self.data_store.get_embouchure_area()))
        self.embouchureAreaEntry.config(state="readonly")

        self.lengthEntry.config(state=tkinter.NORMAL)
        self.lengthEntry.delete(0, tkinter.END)
        self.lengthEntry.insert(0, "%0.4f"%(self.data_store.get_length()))
        self.lengthEntry.config(state="readonly")

    @debugger
    def insideDiaCommand(self, event=None):
        try:
            v = self.insideDiaEntry.get()
            n = float(v)
            if self.data_store.get_inside_dia() != n:
                self.logger.debug("change wall from %f to %f"%(self.data_store.get_inside_dia(), n))
                self.data_store.set_inside_dia(n)
                self.insideDiaEntry.delete(0, tkinter.END)
                self.insideDiaEntry.insert(0, str(n))
                raise_event("CALCULATE_EVENT")
                self.data_store.set_change_flag()
            else:
                self.logger.debug("ignore")
            return True
        except ValueError as e:
            self.logger.error(str(e))
            messagebox.showerror("Error", "Could not convert inside diameter to a floating point number.\nRead value was \"%s\"." % (v))
            self.insideDiaEntry.delete(0, tkinter.END)
            self.insideDiaEntry.insert(0, str(self.data_store.get_inside_dia()))
            return False
        except IndexError:
            self.logger.error(str(e))
            self.wallThicknessEntry.delete(0, tkinter.END)
            self.wallThicknessEntry.insert(0, str(self.data_store.get_wall_thickness()))
        except Exception as e:
            self.logger.error(str(e))
            messagebox.showerror("Unknown Error", "Unknown exception trying to convert inside diameter to a floating point number.\nRead value was \"%s\".\nException: %s" % (v, str(e)))
            self.wallThicknessEntry.delete(0, tkinter.END)
            self.wallThicknessEntry.insert(0, str(self.data_store.get_wall_thickness()))


    @debugger
    def wallThicknessCommand(self, event=None):
        try:
            v = self.wallThicknessEntry.get()
            n = float(v)
            if n != self.data_store.get_wall_thickness():
                self.logger.debug("change wall from %f to %f"%(self.data_store.get_wall_thickness(), n))
                self.data_store.set_wall_thickness(n)
                self.wallThicknessEntry.delete(0, tkinter.END)
                self.wallThicknessEntry.insert(0, str(n))
                raise_event("CALCULATE_EVENT")
                self.data_store.set_change_flag()
            else:
                self.logger.debug("ignore")
            return True
        except ValueError as e:
            self.logger.error(str(e))
            messagebox.showerror("Error", "Could not convert wall thickness to a floating point number.\nRead value was \"%s\"." % (v))
            self.wallThicknessEntry.delete(0, tkinter.END)
            self.wallThicknessEntry.insert(0, str(self.data_store.get_wall_thickness()))
            return False
        except IndexError:
            self.logger.error(str(e))
            self.wallThicknessEntry.delete(0, tkinter.END)
            self.wallThicknessEntry.insert(0, str(self.data_store.get_wall_thickness()))
        except Exception as e:
            self.logger.error(str(e))
            messagebox.showerror("Unknown Error", "Unknown exception trying convert wall thickness to a floating point number.\nRead value was \"%s\".\nException %s" % (v, str(e)))
            self.wallThicknessEntry.delete(0, tkinter.END)
            self.wallThicknessEntry.insert(0, str(self.data_store.get_wall_thickness()))


    @debugger
    def numHolesCommand(self, event=None):
        n = 0
        try:
            v = self.numHolesEntry.get()
            n = int(v)
            if n >= 1 and n <= 12:
                # only raise the event if the number of holes is different from
                # what is in the data_store
                if n != self.data_store.get_number_holes():
                    self.logger.debug("change number of holes from %d to %d"%(self.data_store.get_number_holes(), n))
                    self.data_store.set_number_holes(n)
                    raise_event('UPDATE_LOWER_FRAME_EVENT')
                    self.data_store.set_change_flag()
                else:
                    self.logger.debug("ignore")
                return True
            else:
                self.logger.error("range error on number of holes: %s"%(str(n)))
                messagebox.showerror("Error", message="Number of holes must be an integer between 1 and 12.\nRead value was \"%s\"." % (v))
                self.numHolesEntry.delete(0, tkinter.END)
                self.numHolesEntry.insert(0, str(self.data_store.get_number_holes()))
                return False
        except ValueError as e:
            self.logger.error(str(e))
            messagebox.showerror("Error", message="Could not convert number of holes to an integer.\nRead value was \"%s\"." % (v))
            self.numHolesEntry.delete(0, tkinter.END)
            self.numHolesEntry.insert(0, str(self.data_store.get_number_holes()))
            return False
        except IndexError as e:
            self.logger.error(str(e))
            self.numHolesEntry.delete(0, tkinter.END)
            self.numHolesEntry.insert(0, str(self.data_store.get_number_holes()))
        except Exception as e:
            self.logger.error(str(e))
            messagebox.showerror("Unknown Error", message="Unknown exception trying to convert number of holes to an integer.\nRead value was \"%s\".\nException: %s" % (v, str(e)))
            self.wallThicknessEntry.delete(0, tkinter.END)
            self.wallThicknessEntry.insert(0, str(self.data_store.get_wall_thickness()))


    @debugger
    def displayFormatCallback(self, event):
        if self.displayFormatOpt.current() == 0:
            val = False
        else:
            val = True

        if val != self.data_store.get_disp_frac():
            self.data_store.set_disp_frac(val)
            raise_event("UPDATE_HOLE_EVENT")
            self.logger.debug("current format set to: %s"%(str(self.data_store.get_disp_frac())))
            self.data_store.set_change_flag()
        else:
            self.logger.debug("ignore")


    @debugger
    def measureUnitsCallback(self, event):
        if self.measureUnitsOpt.current() == 0:
            val = False
        else:
            val = True

        if self.data_store.get_units() != val:
            if self.measureUnitsOpt.current() == 1:
                self.displayFormatOpt.config(state=tkinter.DISABLED)
            else:
                self.displayFormatOpt.config(state="readonly")

            self.data_store.set_units(val)
            self.change_units()
            self.logger.debug("current units set to: %s"%(str(self.data_store.get_units())))
            self.data_store.set_change_flag()
        else:
            self.logger.debug("ignore")


    @debugger
    def bellSelectCallback(self, event):
        '''
        Change the data_store to match the new bell selection
        '''
        val = self.bellNoteCombo.current()
        if val != self.data_store.get_bell_note_select():
            self.data_store.set_bell_note_select(val)
            self.data_store.set_bell_freq(self.data_store.note_table[val]['frequency'])
            self.logger.debug("current bell selection set to: %d: %f"%(self.data_store.get_bell_note_select(), self.data_store.get_bell_freq()))
            raise_event("UPDATE_NOTES_EVENT")
            self.data_store.set_change_flag()
        else:
            self.logger.debug("ignore")
        self.set_state()

    @debugger
    def refreshButtonCommand(self):
        self.refreshButton.focus_set()
        self.get_state()
        #raise_event('UPDATE_LINES_EVENT')
        raise_event('UPDATE_LOWER_FRAME_EVENT')
        self.set_state()

    @debugger
    def change_units(self):
        '''
        When this is called, the assumption is that the GUI and the
        data_store have the wrong units. This function takes what ever
        is in the data_sore and converts if to the units that it finds
        there.  Then it updates the GUI.
        '''
        if self.data_store.get_units(): # true of units are mm
            self.data_store.set_inside_dia(utility.in_to_mm(self.data_store.get_inside_dia()))
            self.data_store.set_wall_thickness(utility.in_to_mm(self.data_store.get_wall_thickness()))
        else:
            self.data_store.set_inside_dia(utility.mm_to_in(self.data_store.get_inside_dia()))
            self.data_store.set_wall_thickness(utility.mm_to_in(self.data_store.get_wall_thickness()))

        self.set_state()
        # Cause the other frames to update
        raise_event("CHANGE_UNITS_EVENT")
        raise_event('CALCULATE_EVENT')
        self.data_store.set_change_flag()

    @debugger
    def setTitleCommand(self, event=None):
        try:
            title = self.titleEntry.get()
            old_title = self.data_store.get_title()
            if title != old_title:
                self.data_store.set_title(title)
                self.logger.debug("title set to: \"%s\""%(str(self.data_store.get_title())))
                self.data_store.set_change_flag()
            else:
                self.logger.debug("ignore")
        except IndexError:
            pass # always ignore
Пример #6
0
class Calculator:
    def __init__(self):
        # constant data
        self.logger = Logger(self, Logger.INFO)
        self.logger.debug("enter constructor")
        #self.configuration = Configuration.get_instance()
        self.data = DataStore.get_instance()
        self.logger.debug("end constructor")
        register_event("CALCULATE_EVENT", self.do_calc)

        # self.isound = self.data.get_vsound_in()
        # self.msound = self.data.get_vsound_mm()

        self.max_loop = 12
        self.max_delta = 0.0001

    @debugger
    def update(self):
        '''
        Make all calculations based on the current state.
        '''
        pass

    @debugger
    def do_calc(self):
        # self.isound = self.data.get_vsound_in()
        # self.msound = self.data.get_vsound_mm()
        self.data.clear_hole_data()
        if self.data.get_calc_type() == 0:
            self.quadratic()
            #self.iterative()
        else:
            self.iterative()
        raise_event("UPDATE_LINES_EVENT")
        raise_event("UPDATE_UPPER_EVENT")

    @debugger
    def closedCorrection(self, index):
        # b = self.data.get_inside_dia()
        # holeSize = self.data.get_hole_size(index)
        # p = (holeSize / b) * (holeSize / b)
        p = math.pow(
            self.data.get_hole_size(index) / self.data.get_inside_dia(), 2)
        retv = (self.data.get_wall_thickness() * p) / 4.0
        return retv

    @debugger
    def effectiveThickness(self, index):
        return self.data.get_wall_thickness() + (
            self.data.get_chim_const() * self.data.get_hole_size(index))

    # C_emb = distance from theoretical start of air column to center of embouchure hole;
    # the air column effectively extends beyond the blow hole center by this distance.
    # (the cork face should be about 1 to 1.5 embouchure diameters from emb. center)
    # C_emb := (Bore/Demb)*(Bore/Demb)*(wall+0.75*Demb); // per spreadsheet
    # C_emb := (Bore/Demb)*(Bore/Demb)*(Bore/2 + wall + 0.6133*Demb/2); // an alternative
    # C_emb := (Bore/Demb)*(Bore/Demb)*10.84*wall*Demb/(Bore + 2*wall); // kosel's empirical fit
    #
    # The area calculated must be translated back to a diameter. Then these formulas can be
    # applied correctly.
    @debugger
    def embouchureCorrection(self):
        # this "diameter" could be square, oval or round
        embDia = 2.0 * math.sqrt(self.data.get_embouchure_area() / math.pi)

        p = math.pow(self.data.get_inside_dia() / embDia, 2)
        # after testing these three formulae, the only one that is close if the first one.
        embDst = p * (self.data.get_wall_thickness() + 0.75 * embDia)
        #embDst = p * (self.data.get_inside_dia() / 2 + self.data.get_wall_thickness() + 0.6133 * embDia / 2)
        #embDst = p * 10.84 * self.data.get_wall_thickness() * embDia / (self.data.get_inside_dia() + 2 * self.data.get_wall_thickness())

        return embDst

    @debugger
    def holeSpacing(self, index):
        holeSpacing = 0.0
        if (index == 0):
            holeSpacing = self.data.get_end_location(
            ) - self.data.get_hole_location(index)
        else:
            holeSpacing = self.data.get_hole_location(
                index - 1) - self.data.get_hole_location(index)

        return holeSpacing

    @debugger
    def endCorrection(self):
        return self.data.get_ecorr() * self.data.get_inside_dia(
        ) / 2  # original flutomat

    @debugger
    #def firstHoleDistance(self, index):
    def firstHoleDistance(self):
        # // Cfg.open[1] = Cfg.height[1] /
        # // ((double) pow((double) (Cfg.diacent[1]/Cfg.borecent), 2.0) +
        # // Cfg.height[1] * (1.0F / Cfg.hs[1]));
        # final double bore = hole.whistle.bore;
        pow = ((self.data.get_hole_size(0) / self.data.get_inside_dia()) *
               (self.data.get_hole_size(0) / self.data.get_inside_dia()))
        holeSp = self.holeSpacing(0)
        e = self.effectiveThickness(0)
        q = e * (1.0 / holeSp)
        r = pow + q
        openCorrection = e / r
        return openCorrection

    @debugger
    def subsequentHoleDistance(self, index):
        # // Cfg.open[n] = Cfg.hs[n] * 0.5F *
        # // ( (double) sqrt((double) 1.0F + 4.0F * Cfg.height[n] / Cfg.hs[n] *
        # // (double) pow((double) (Cfg.borecent / Cfg.diacent[n]), 2.0)) - 1.0F);
        # final double bore = hole.whistle.bore;
        a = self.data.get_inside_dia() / self.data.get_hole_size(index)
        b = a * a
        holeSp = self.holeSpacing(index)
        c = 4.0 * self.effectiveThickness(index) / holeSp * b
        d = math.sqrt(1.0 + c)
        openCorrection = holeSp * 0.5 * (d - 1.0)
        return openCorrection

    @debugger
    def cutoffFrequency(self, index):
        dist = self.data.get_hole_location(
            index - 1) - self.data.get_hole_location(index)
        sqrtTerm = math.sqrt(self.effectiveThickness(index) * dist)
        ratio = self.data.get_vsound() / (2 * math.pi)
        ratio = ratio * (self.data.get_hole_size(index) /
                         self.data.get_inside_dia())
        ratio = ratio / sqrtTerm
        return ratio

    @debugger
    def iterative(self):
        # Calculate position of end hole
        xEnd = self.data.get_vsound() / (2 * self.data.get_bell_freq())
        xEnd = xEnd - self.endCorrection()
        for i in range(self.data.get_number_holes()):
            xEnd = xEnd - self.closedCorrection(i)
        self.data.set_end_location(xEnd)

        # find first finger hole location
        nominalPosition = self.data.get_vsound() / (2 *
                                                    self.data.get_hole_freq(0))
        self.data.set_hole_location(0, 0.0)
        delta = 10.0

        for i in range(self.max_loop):
            oldPosition = self.data.get_hole_location(0)
            self.data.set_hole_location(
                0, nominalPosition - self.firstHoleDistance())
            self.data.print_data()

            for h in range(1, self.data.get_number_holes()):
                loc = self.data.get_hole_location(0)
                loc -= self.closedCorrection(h)
                self.data.set_hole_location(0, loc)

            delta = math.fabs(self.data.get_hole_location(0) - oldPosition)
            if delta < self.max_delta:
                break

        # set subsequent finger hole locations
        for holeNum in range(1, self.data.get_number_holes()):
            # final Hole hole = whistle.hole[holeNum]
            nominalPosition = self.data.get_vsound() / (
                2 * self.data.get_hole_freq(holeNum))
            self.data.set_hole_location(holeNum, 0.0)
            delta = 10.0
            for i in range(self.max_loop):
                oldPosition = self.data.get_hole_location(holeNum)
                self.data.set_hole_location(
                    holeNum,
                    nominalPosition - self.subsequentHoleDistance(holeNum))
                for h in range(holeNum + 1, self.data.get_number_holes()):
                    loc = self.data.get_hole_location(holeNum)
                    loc -= self.closedCorrection(h)
                    self.data.set_hole_location(holeNum, loc)

                delta = math.fabs(
                    self.data.get_hole_location(holeNum) - oldPosition)

        self.data.set_length(self.data.get_end_location() -
                             self.embouchureCorrection())
        for holeNum in range(self.data.get_number_holes()):
            self.data.set_hole_cutoff(holeNum, self.cutoffFrequency(holeNum))
            self.data.set_hole_rcutoff(
                holeNum,
                self.data.get_hole_cutoff(holeNum) /
                self.data.get_hole_freq(holeNum))
            self.data.set_hole_xloc(
                holeNum,
                self.data.get_end_location() -
                self.data.get_hole_location(holeNum))
            if holeNum == 0:
                self.data.set_hole_diff(
                    0,
                    self.data.get_end_location() -
                    self.data.get_hole_location(holeNum))
            else:
                self.data.set_hole_diff(
                    0,
                    self.data.get_hole_location(holeNum - 1) -
                    self.data.get_hole_location(holeNum))

    @debugger
    def quadratic(self):
        # Calculate position of end hole
        xEnd = self.data.get_vsound() / (2 * self.data.get_bell_freq())
        xEnd = xEnd - self.endCorrection()

        for i in range(self.data.get_number_holes()):
            xEnd -= self.closedCorrection(i)
        self.data.set_end_location(xEnd)

        # Calculate the position of the first tone hole
        length = self.data.get_vsound() / (2 * self.data.get_hole_freq(0))
        for i in range(1, self.data.get_number_holes()):
            length = length - self.closedCorrection(i)

        try:
            h = self.data.get_hole_size(0)
            a = h / self.data.get_inside_dia()
            a = a * a
            b = -(xEnd + length) * a
            c = (xEnd * length) * a
            c += self.effectiveThickness(0) * (length - xEnd)
            v = (b * b) - (4.0 * a * c)
            self.data.set_hole_location(0, (-b - math.sqrt(math.fabs(v))) /
                                        ((2 * a)))

            # find subsequent finger hole locations
            for holeNum in range(1, self.data.get_number_holes()):
                length = self.data.get_vsound() / (
                    2.0 * self.data.get_hole_freq(holeNum))
                for i in range(holeNum + 1, self.data.get_number_holes()):
                    length = length - self.closedCorrection(i)

                a = 2.0
                ratio = self.data.get_inside_dia() / self.data.get_hole_size(
                    holeNum)
                ratio = ratio * ratio * self.effectiveThickness(holeNum)

                prevHole = self.data.get_hole_location(holeNum - 1)

                b = -prevHole - (3.0 * length)
                b = b + ratio
                c = length - ratio
                c = c * prevHole
                c = c + length * length
                v = (b * b) - (4 * a * c)
                self.data.set_hole_location(
                    holeNum, (-b - math.sqrt(math.fabs(v))) / ((2 * a)))
        except ValueError as e:
            self.logger.error("%s: a = %f, b = %f, c = %f, v = %f" %
                              (str(e), a, b, c, v))

        #self.embouchureCorrection()
        self.data.set_length(self.data.get_end_location() -
                             self.embouchureCorrection())
        for holeNum in range(self.data.get_number_holes()):
            self.data.set_hole_cutoff(holeNum, self.cutoffFrequency(holeNum))
            self.data.set_hole_rcutoff(
                holeNum,
                self.data.get_hole_cutoff(holeNum) /
                self.data.get_hole_freq(holeNum))
            self.data.set_hole_xloc(
                holeNum,
                self.data.get_end_location() -
                self.data.get_hole_location(holeNum))
            if holeNum == 0:
                self.data.set_hole_diff(
                    0,
                    self.data.get_end_location() -
                    self.data.get_hole_location(holeNum))
            else:
                self.data.set_hole_diff(
                    holeNum,
                    self.data.get_hole_location(holeNum - 1) -
                    self.data.get_hole_location(holeNum))