def _genHeader(self, header): """ Generate report header. :param header: Header band. :return: True/False. """ try: # log_func.debug(u'Generate header') # We will add to the end of the report, therefore, determine the maximum line max_row = len(self._Rep['sheet']) i_row = 0 cur_height = 0 for row in range(header['row'], header['row'] + header['row_size']): for col in range(header['col'], header['col'] + header['col_size']): if self._TemplateSheet[row][col]: self._genCell(self._TemplateSheet, row, col, self._Rep, max_row+i_row, col, self._CurRec) cur_height = self._TemplateSheet[row][col]['height'] i_row += 1 # Current coordinate Y self._cur_top += cur_height self._Rep['header'] = {'row': max_row, 'col': header['col'], 'row_size': i_row, 'col_size': header['col_size'], } # Clear sums self._TemplateSheet = self._clearSum(self._TemplateSheet, 0, len(self._TemplateSheet)) return True except: log_func.fatal(u'Error report header generate <%s>.' % str_func.toUnicode(self._RepName)) return False
def _genFooter(self, footer): """ Generate report footer. :param footer: Footer band. :return: True/False. """ try: if not footer: return True # We will add to the end of the report, therefore, determine the maximum line max_row = len(self._Rep['sheet']) i_row = 0 # Row band count cur_height = 0 for row in range(footer['row'], footer['row'] + footer['row_size']): for col in range(footer['col'], footer['col'] + footer['col_size']): if self._TemplateSheet[row][col]: self._genCell(self._TemplateSheet, row, col, self._Rep, max_row+i_row, col, self._CurRec) cur_height = self._TemplateSheet[row][col]['height'] i_row += 1 # Current Y coordinate self._cur_top += cur_height self._Rep['footer'] = {'row': max_row, 'col': footer['col'], 'row_size': i_row, 'col_size': footer['col_size'], } return True except: log_func.fatal(u'Error report footer generate <%s>.' % self._RepName) return False
def setPinMarker(self, geo_latitude, geo_longitude, color='blue', icon=None, popup_text=u'', tooltip_text=u''): """ Adding a pointer marker to the map. :param geo_latitude: Geographic latitude. :param geo_longitude: Geographic longitude. :param color: Marker color. :param icon: Marker icon. :param popup_text: Marker pop-up text. A tooltip appears by clicking on the marker. :param tooltip_text: Marker tooltip text. A tooltip appears when you hover the mouse over the marker. :return: True/False. """ if self._geo_map is not None: try: marker = self._rendering.Marker( location=[geo_latitude, geo_longitude], popup=popup_text if popup_text else None, tooltip=tooltip_text if tooltip_text else None, icon=icon) marker.add_to(self._geo_map) # log_func.debug(u'Pin marker created. Geolocation [%s x %s]' % (geo_latitude, geo_longitude)) return True except: log_func.fatal(u'Error adding a pointer marker to the map') else: log_func.warning(u'Map object not defined to add a pointer marker') return False
def _initSumCell(self, cell): """ Init cell sum. :param cell: Cell data. :return: Returns the corrected cell description. In case of an error, returns the old description of the cell. """ try: new_cell = cell cell_val = new_cell['value'] if cell_val is not None and not isinstance(cell_val, str): cell_val = str(cell_val) parsed_fmt = self.parseFuncText(cell_val, [REP_SYS_PATT]) for cur_func in parsed_fmt['func']: # System function if re.search(REP_SYS_PATT, cur_func): # Sum function if cur_func[2:6].lower() in ('sum(', 'avg('): # Init sum if new_cell['sum'] is None: new_cell['sum'] = [] new_cell['sum'].append(copy.deepcopy(REP_SUM)) new_cell['sum'][-1]['formul'] = cur_func[6:-3].replace(REP_SUM_FIELD_START, 'record[\'').replace(REP_SUM_FIELD_STOP, '\']') return new_cell except: log_func.fatal(u'Error init cell sum <%s>' % cell) return cell
def _execLambda(self, cur_func, locals, globals): """ Execute lambda. Lambda haa 1 argument. It is record. For example: [~rec: rec['name']=='My name'~] :param cur_func: Call lambda text. :param locals: Local name space. :param globals: Global name space. :return: The calculated value as a string or an empty string in case of an error. """ value = u'' lambda_body = cur_func[2:-2] lambda_func = None try: lambda_func = eval('lambda ' + cur_func[2:-2]) except: log_func.fatal(u'Error lambda format <%s>' % lambda_body) if lambda_func: try: record = locals['record'] if 'record' in locals else globals.get('record', dict()) value = str(lambda_func(record)) except: log_func.fatal(u'Error lambda execute <%s>' % lambda_body) return value
def _getReportParameters(self, report=None): """ Get report parameters. :param report: Report template data. :return: Report parameters dictionary: {'report_parameter_name': report_parameter_value, ... }. """ try: if report is not None: self._Rep = report else: report = self._Rep # 1. Get query table query = report['query'] if query is not None: if self._isQueryFunc(query): query = self._execQueryFunc(query) else: query = exec_func.execTxtFunction(query) return query except: log_func.fatal(u'Error get report parameters <%s>' % report['name']) return None
def openReportBrowser(parent_form=None, report_dir='', mode=REPORT_EDITOR_MODE): """ Launch report browser. :param parent_form: The parent form, if not specified, creates a new application. :param report_dir: Directory where reports are stored. :return: True/False. """ app = wx.GetApp() if app is None: app = wx.App() log_func.info(u'wxPython version: %s' % wx.VERSION_STRING) dlg = None try: dlg = iqReportBrowserDialog(parent=parent_form, mode=mode, report_dir=report_dir) dlg.ShowModal() dlg.Destroy() return True except: if dlg: dlg.Destroy() log_func.fatal(u'Error starting report browser') return False
def _genUnder(self, under): """ Generate report under. :param under: Under band. :return: True/False. """ try: if 'row' not in under or 'col' not in under or \ 'row_size' not in under or 'col_size' not in under: self._Rep['under'] = under return True max_row = len(self._Rep['sheet']) i_row = 0 cur_height = 0 for row in range(under['row'], under['row'] + under['row_size']): for col in range(under['col'], under['col'] + under['col_size']): if self._TemplateSheet[row][col]: self._genCell(self._TemplateSheet, row, col, self._Rep, max_row+i_row, col, self._CurRec) cur_height = self._TemplateSheet[row][col]['height'] i_row += 1 self._cur_top += cur_height self._Rep['under'] = copy.deepcopy(under) self._Rep['under']['row'] = max_row self._Rep['under']['row_size'] = i_row return True except: log_func.fatal(u'Error report under generate <%s>' % self._RepName) return False
def generateReport(self, report=None, *args, **kwargs): """ Run report generator. :param report: Report template data. :return: Generated report or None if error. """ try: if report is not None: self._report_template = report # 1. Get query table # Variables variables = kwargs.get('variables', None) if variables: kwargs.update(variables) query_tbl = self.getQueryTbl(self._report_template) if not query_tbl or not query_tbl['__data__']: if not global_func.isCUIEngine(): if dlg_func.openAskBox(u'WARNING', u'No report data\nQuery: %s\nContinue report generation?' % self._report_template['query']): return None else: log_func.warning(u'No report data. Continue generation.') query_tbl = self.createEmptyQueryTbl() # 2. Run generation rep = report_generator.iqReportGenerator() data_rep = rep.generate(self._report_template, query_tbl) return data_rep except: log_func.fatal(u'Error generate report <%s>' % self._report_template['name']) return None
def createNewByOffice(self, dst_path=None): """ Create a new report using LibreOffice Calc. :param dst_path: Destination report folder path. """ try: src_filename = DEFAULT_REP_TMPL_FILE new_filename = dlg_func.getTextEntryDlg(self._parent_window, u'Create new', u'Enter a file name for the report template') if os.path.splitext(new_filename)[1] != '.ods': new_filename += '.ods' if dst_path is None: # It is necessary to determine the resulting path dst_path = dlg_func.getDirDlg(self._parent_window, u'Report folder') if not dst_path: dst_path = os.getcwd() dst_filename = os.path.join(dst_path, new_filename) if os.path.exists(dst_filename): if dlg_func.openAskBox(u'Rewrite existing file?'): shutil.copyfile(src_filename, dst_filename) else: shutil.copyfile(src_filename, dst_filename) cmd = '%s %s' % (UNIX_OFFICE_OPEN, dst_filename) log_func.debug(u'Command <%s>' % str_func.toUnicode(cmd)) os.system(cmd) return True except: log_func.fatal(u'Error create new report template by LibreOffice Calc')
def _getData(self, rows): """ Get data. """ try: data = list() i_rec = 0 for row in rows: rec = list() # Empty cells if 'Index' in row: idx = int(row['Index']) if idx > i_rec: data += [[]] * (idx - i_rec) for cell in row['_children_']: cell_data = None if 'value' in cell['_children_'][0]: cell_data = cell['_children_'][0]['value'] rec.append(cell_data) data.append(rec) i_rec = len(data) return data except: log_func.fatal(u'Error report data') return None
def viewSQLQueryDlg(parent=None, db=None, sql_txt=None): """ View SQL query result dialog. :param parent: Parent window. :param db: Database object. :param sql_txt: SQL query text. :return: True/False. """ if parent is None: parent = global_func.getMainWin() dlg = None try: dlg = iqViewSQLQueryDialog(parent) dlg.setDB(db) dlg.setSQLQuery(sql_txt) dlg.init() dlg.ShowModal() dlg.Destroy() return True except: log_func.fatal(u'Error view SQL query result dialog') if dlg: dlg.Destroy() return False
def generateReport(self, report=None, *args, **kwargs): """ Generate report. :param report: Report template data. :return: Generated report or None if error. """ try: if report is not None: self._report_template = report # 1. Get query table query_data = self.getQueryTbl(self._report_template) if not query_data: dlg_func.openWarningBox(u'WARNING', u'Not report data\nQuery <%s>' % self._report_template['query'], parent=self._parent_window) return None # 2. Generate rep_data = copy.deepcopy(self._report_template) rep_data['__data__'] = query_data return rep_data except: log_func.fatal(u'Error generate report <%s>' % self._report_template['name']) return None
def editIndicatorConstructorDlg(parent=None, indicator=None): """ Start editing the filter indicator. :param parent: Parent window. :param indicator: Indicator state. :return: Edited indicator list or None if CANCEL is pressed. """ try: if parent is None: parent = iq.getMainWin() dlg = iqIndicatorConstructorDlg(parent) dlg.init() dlg.setIndicator(indicator=indicator, refresh_ctrl=True) result = dlg.ShowModal() if result == wx.ID_OK: indicator = dlg.getIndicator() dlg.Destroy() log_func.debug(u'List of edited filter indicator %s' % str(indicator)) return indicator except: log_func.fatal(u'Filter indicator editing error') return None
def existsColumns(dbf_filename, columns, auto_create=True): """ Exists columns in DBF table? :param dbf_filename: DBF filename. :param columns: Column list: [(column name, column tyle, length, default value), ...] :param auto_create: Create automatic column if not exists? :return: True/False. """ results = list() try: fields = getDBFFieldNames(dbf_filename) results = [column[0] in fields for column in columns] for column in columns: column_name = column[0] if column_name not in fields: if auto_create: column_type = column[1] column_len = column[2] if len(column) > 2 else 0 column_default = column[3] if len(column) > 3 else None appendDBFNewField(dbf_filename, column_name, column_type, column_len, default=column_default) except: log_func.fatal(u'Error exists columns ini DBF table') return all(results)
def _genGrpFooter(self, rep_group): """ Generate group footer. :param rep_group: REP_GRP dictionary. :return: True/False. """ try: band = rep_group['footer'] if not band: return False max_row = len(self._Rep['sheet']) i_row = 0 cur_height = 0 for row in range(band['row'], band['row']+band['row_size']): for col in range(band['col'], band['col']+band['col_size']): if self._TemplateSheet[row][col]: self._genCell(self._TemplateSheet, row, col, self._Rep, max_row + i_row, col, rep_group['old_rec']) cur_height = self._TemplateSheet[row][col]['height'] i_row += 1 # Current Y coordinate self._cur_top += cur_height return True except: log_func.fatal(u'Error group footer generate <%s> of report <%s>.' % (rep_group['field'], self._RepName)) return False
def startSheet(self, rep_name, report): """ Start worksheet. :param rep_name: Report name. :param report: Report data. """ rep_name = str(rep_name) self.startElementLevel('Worksheet', {'ss:Name': rep_name}) try: if report['upper']: refers_to = self._getUpperRangeStr(report['upper']) self.startElementLevel('Names', {}) self.startElementLevel('NamedRange', { 'ss:Name': 'Print_Titles', 'ss:RefersTo': refers_to }) self.endElementLevel('NamedRange') self.endElementLevel('Names') except: log_func.fatal('Names SAVE <%s>' % report['upper']) raise self.startElementLevel('Table', {})
def _genSubReport(self, sub_rep_name, row): """ Generate sub report. :param sub_rep_name: Sub report name. :param row: Rown number for insert sub report. :return: True/False. """ try: if '__sub__' in self._QueryTbl and self._QueryTbl['__sub__']: if sub_rep_name in self._QueryTbl['__sub__']: # If there is sub-report data, then start the generation report = self._QueryTbl['__sub__'][sub_rep_name]['report'] if isinstance(report, str): from . import report_template template = report_template.iqlXMLSpreadSheetReportTemplate() self._QueryTbl['__sub__'][sub_rep_name]['report'] = template.read(report) # Generate sub report rep_gen = iqReportGenerator() rep_result = rep_gen.generate(self._QueryTbl['__sub__'][sub_rep_name]['report'], self._QueryTbl['__sub__'][sub_rep_name], self._QueryTbl['__sub__'][sub_rep_name]['__variables__'], self._QueryTbl['__sub__'][sub_rep_name]['__coord_fill__']) self._Rep['sheet'] = self._Rep['sheet'][:row]+rep_result['sheet']+self._Rep['sheet'][row:] return True except: log_func.fatal(u'Error sub report generate <%s> of report <%s>.' % (sub_rep_name, self._RepName)) return False
def viewTransforDataSourceDlg(parent=None, component=None): """ View transform datasource result dialog. :param parent: Parent window. :param component: Testing component. :return: True/False. """ if component is None: log_func.warning(u'Type error testing component') return False if parent is None: parent = global_func.getMainWin() dlg = None try: dlg = iqViewTransformDataSourceDialog(parent) dlg.setTestingComponent(component) dlg.init() dlg.ShowModal() dlg.Destroy() return True except: log_func.fatal(u'Error view transform datasource result dialog') if dlg: dlg.Destroy() return False
def _execCodeBlock(self, cur_func, locals, globals): """ Execute code block. In the code block, new_cell and record objects are available. If you need to display information, then it must be displayed in the variable value. For example: [=value = '-' if record['name']=='My name' else ''=] :param cur_func: Code block text. :param locals: Local name space. :param globals: Global name space. :return: The calculated value as a string or an empty string in case of an error. """ value = u'' exec_func = cur_func[2:-2].strip() try: exec(exec_func, globals, locals) # When the code block is executed, the value of the variable is located in the locals namespace. # Therefore, after executing the code block, it is necessary # to return the variable back to the current function value = locals.get('value', u'') log_func.debug(u'Execute code block <%s>. Value [%s]' % (exec_func, value)) except: log_func.fatal(u'Error code block execute <%s>' % str_func.toUnicode(exec_func)) return str(value)
def _genGrpHeader(self, rep_group): """ Generate group header. :param rep_group: REP_GRP dictionary. :return: True/False. """ try: band = rep_group['header'] if not band: return False # We will add to the end of the report, therefore, determine the maximum line max_row = len(self._Rep['sheet']) i_row = 0 cur_height = 0 for row in range(band['row'], band['row']+band['row_size']): for col in range(band['col'], band['col']+band['col_size']): if self._TemplateSheet[row][col]: self._genCell(self._TemplateSheet, row, col, self._Rep, max_row+i_row, col, self._CurRec) cur_height = self._TemplateSheet[row][col]['height'] i_row += 1 # Current Y coordinate self._cur_top += cur_height # Clear sums. There are no summary cells in the headers band = rep_group['footer'] if band: self._TemplateSheet = self._clearSum(self._TemplateSheet, band['row'], band['row']+band['row_size']) return True except: log_func.fatal(u'Error group header generate <%s> of report <%s>.' % (rep_group['field'], self._RepName)) return False
def initComboBoxScanners(self, select_scanner=None): """ Initialization of the combobox list of system scanners. :param select_scanner: Which scanner to choose after initialization of the combo box, if None, then the first one in the list is selected. """ scanner_devices = self.scan_manager.getDeviceNames() self.scanner_comboBox.Clear() if scanner_devices: default_select = 0 i = 0 for scanner_name in scanner_devices: img_filename = os.path.normpath(os.path.join(os.path.dirname(__file__), u'img', u'scanner.png')) if scanner_name == select_scanner: default_select = i self.scanner_comboBox.Append(scanner_name, wx.Image.ConvertToBitmap(wx.Image(img_filename))) i += 1 self.scanner_comboBox.Select(default_select) else: log_func.warning(u'No scan devices found') msg = u'No scan devices found. Check if the devices are on / connected to them.' dlg_func.openWarningBox(u'WARNING', msg) try: self.EndModal(wx.ID_CANCEL) except: log_func.fatal()
def onAddToolClicked(self, event): """ Handler for the button for adding an indicator state. """ try: self.setDefaultStateCtrlValue() state_indicator = self.getStateCtrlValue() new_name = state_indicator['name'] # new_image = state_indicator.get('image', None) # new_exp = state_indicator.get('expression', None) # Add indicator state to list self._indicator.append(state_indicator) # Add a line to the list # self.appendRow_list_ctrl(ctrl=self.indicator_listCtrl, row=(new_name, None, None), # auto_select=True) self.appendListCtrlRow(listctrl=self.indicator_listCtrl, row=(new_name, None, None), auto_select=True) # self.ctrl_toolBar.EnableTool(self.save_tool.GetId(), True) except: log_func.fatal(u'Error adding indicator state') event.Skip()
def setChoices(self, table_data=None, is_empty=True): """ Setting the picklist. :param table_data: Table data. :param is_empty: Is there an empty string in the list? :return: True/False. """ if table_data is None: table_data = self.getTableData() else: self._table_data = table_data if table_data is not None: # First, remove all elements self.Clear() # Then fill in try: if is_empty: self.Append(u'') for record in table_data: label = self.getLabel(record, table_data) self.Append(label) self.SetSelection(0) return True except: log_func.fatal(u'Error filling select list with data') else: log_func.warning(u'Not defined table data in control <%s>' % self.getName()) return False
def getSelectedRecord(self, table_data=None, selected_idx=-1): """ Get the selected record by the index of the selected item. :param table_data: Table data. :param selected_idx: The index of the selected item. :return: Dictionary of the selected entry, or None on error. """ if selected_idx < 0: # Nothing selected selected_idx = self.GetSelection() - (1 if self.getCanEmpty() else 0) if selected_idx < 0: # Nothing selected return None if table_data is None: table_data = self.getTableData() if table_data is not None: records = table_data len_records = len(records) if 0 <= selected_idx < len_records: try: record = records[selected_idx] return record except: log_func.fatal(u'Error retrieving selected record') else: log_func.warning(u'Incorrect index <%d>. Number of records <%d>' % (selected_idx, len_records)) else: log_func.warning(u'Not defined table data in control <%s>' % self.getName()) return None
def scan(self, scan_filename=None): """ Scan a document and save it to a file. :param scan_filename: The name of the scan file. If the file name is not specified, then scanning and returns the PIL.Image object. :return: Scan file name or PIL.Image object. None - in case of an error. """ try: image = self.scan_device_obj.snap() if scan_filename: image.save(scan_filename) return scan_filename # Do not save to file. We need a scan image object. return image except: log_func.fatal(u'Scan error') # So we display scanning errors trace_txt = traceback.format_exc() if DOC_FEEDER_JAMMED_ERR in trace_txt: self.showScanErrorMsg( u'Document misfeed in the paper feed tray') return None
def setScanOptions(self, **options): """ Set Scan Options :param options: Options. :return: True/False. """ try: global SCAN_OPTIONS_ORDER for option_name in SCAN_OPTIONS_ORDER: if option_name in options: option_val = options[option_name] try: setattr(self.scan_device_obj, option_name, option_val) log_func.info(u'Set scan option <%s>. Value <%s>' % (option_name, option_val)) # Remember the option values set. # It may be that we install the options in the device, # but for some reason they are not set :-( self.options[option_name] = option_val except: log_func.warning( u'Error setting scan option <%s>. Value <%s>' % (option_name, option_val)) return True except: log_func.fatal(u'Error setting scan options') return False
def getPythonScriptDialog(parent=None, script=None): """ Open dialog. :param parent: Parent window. :param script: Python script text. :return: Script text or None if Cancel button clicked. """ dialog = None try: if parent is None: parent = global_func.getMainWin() dialog = iqPythonScriptDialog(parent) dialog.init() if script is not None: dialog.source_scintilla.SetText(script) result = dialog.ShowModal() new_script = dialog.script dialog.Destroy() return new_script if result == wx.ID_OK else None except: if dialog: dialog.Destroy() log_func.fatal(u'Error open dialog <iqPythonScriptDialog>') return None
def selectPostAction(self, report_filename, parent=None, db_url=None, sql=None, command=None, stylelib_filename=None, variables=None): """ Select the action we want to do with the report after generating the report. :param report_filename: The name of the report template file. Paths are relative to the report folder. :param db_url: Connection string as url. For example: postgresql+psycopg2://postgres:[email protected]:5432/realization. :param sql: SQL query. :param command: Command after generation (print/preview/export). :param stylelib_filename: Style library file. :param variables: Dictionary of variables to populate the report. :return: True/False. """ try: return do_report.selectReport(report_filename=report_filename, report_dir=self.getReportDir(), db_url=db_url, sql=sql, command=command, stylelib_filename=stylelib_filename, variables=variables) except: log_func.fatal(u'Error select post action report <%s>' % report_filename)
def previewOffice(self, xls_filename): """ Open preview in Office. :param xls_filename: Report XLS filename. """ if not os.path.exists(xls_filename): log_func.warning(u'Preview. Report file <%s> not exists' % xls_filename) return False pdf_filename = os.path.splitext(xls_filename)[0] + PDF_FILENAME_EXT if os.path.exists(pdf_filename): try: os.remove(pdf_filename) except: log_func.fatal(u'Error delete file <%s>' % pdf_filename) if sys_func.isLinuxPlatform(): cmd = report_gen_system.UNIX_CONV_TO_PDF_FMT % xls_filename log_func.info(u'Convert to PDF. Execute command <%s>' % cmd) os.system(cmd) if os.path.exists(pdf_filename): cmd = report_gen_system.UNIX_OPEN_PDF_FMT % pdf_filename log_func.info(u'Open PDF. Execute command <%s>' % cmd) os.system(cmd) return True else: log_func.warning(u'Open PDF. PDF file <%s> not found' % pdf_filename) elif sys_func.isWindowsPlatform(): win_conv_to_pdf_fmt = iq.KERNEL.settings.THIS.SETTINGS.win_conv_to_pdf_fmt.get( ) if not win_conv_to_pdf_fmt: win_conv_to_pdf_fmt = report_gen_system.WIN_CONV_TO_PDF_FMT cmd = win_conv_to_pdf_fmt % (xls_filename, os.path.dirname(xls_filename)) log_func.info(u'Convert to PDF. Execute command <%s>' % cmd) os.system(cmd) if os.path.exists(pdf_filename): win_open_pdf_fmt = iq.KERNEL.settings.THIS.SETTINGS.win_open_pdf_fmt.get( ) if not win_open_pdf_fmt: win_open_pdf_fmt = report_gen_system.WIN_OPEN_PDF_FMT cmd = win_open_pdf_fmt % pdf_filename log_func.info(u'Open PDF. Execute command <%s>' % cmd) os.system(cmd) return True else: log_func.warning(u'Open PDF. PDF file <%s> not found' % pdf_filename) else: log_func.warning(u'Unsupported <%s> platform' % sys_func.getPlatform()) return False