def getReportResourceFilename(report_filename='', report_dir=''): """ Получить полное имя файла шаблона отчета. @param report_filename: Имя файла отчета в кратком виде. @param report_dir: Папка отчетов. @return: Полное имя файла отчета. """ # Проверить расширение rprt_filename = report_filename if not rprt_filename.endswith(DEFAULT_REPORT_FILE_EXT): rprt_filename = os.path.splitext( rprt_filename)[0] + DEFAULT_REPORT_FILE_EXT # Проверить актуальность шаблона full_src_filename = getPathFilename(report_filename, report_dir) full_rprt_filename = getPathFilename(rprt_filename, report_dir) if isNewReportTemplateFile(full_src_filename, full_rprt_filename): # Если исходный шаблон изменен позже чем рабочий файл шаблона <rprt> # то необходимо сделать изменения updateReportTemplateFile(full_src_filename, full_rprt_filename) if os.path.exists(rprt_filename): # Проверить может быть задано абсолютное имя файла filename = rprt_filename else: # Задано скорее всего относительное имя файла # относительно папки отчетов filename = full_rprt_filename if not os.path.exists(filename): # Нет такого файла log.warning(u'Файл шаблона отчета <%s> не найден' % textfunc.toUnicode(filename)) filename = createReportResourceFile(filename) log.debug(u'Полное имя файла шаблона <%s>' % textfunc.toUnicode(filename)) return filename
def setExtOptions(self, **options): """ Установить дополнительные опции. @param options: Словарь опций. """ log.debug(u'Опции сканирования: %s' % options) if options: if 'scanner' in options: self.scanner = options.get('scanner', None) if 'source' in options: self.scan_source = options.get('source', None) if 'mode' in options: self.scan_mode = options.get('mode', None) if 'is_multi_scan' in options: self.is_multi_scan = options.get('is_multi_scan', None) if 'is_preview' in options: self.is_preview = options.get('is_preview', None) if 'page_size' in options: self.page_size = options.get('page_size', None) if 'area' in options: self.scan_area = options.get('area', None) if 'scan_dir' in options: self.scan_dir = options.get('scan_dir', None) if 'file_name' in options: self.scan_filename = options.get('file_name', None) if 'file_type' in options: self.scan_filetype = options.get('file_type', None) if 'depth' in options: self.depth = options.get('depth', None) if 'ext_scan_cmd' in options: self.ext_scan_cmd = options.get('ext_scan_cmd', None) else: log.warning(u'Не определены опции сканирования для установки')
def NewByOffice(self, dst_path=None): """ Создание нового отчета средствами LibreOffice Calc. @param dst_path: Результирующая папка, в которую будет помещен новый файл. """ try: src_filename = DEFAULT_REP_TMPL_FILE new_filename = dlg.getTextInputDlg( self._ParentForm, u'Создание нового файла', u'Введите имя файла шаблона отчета') if os.path.splitext(new_filename)[1] != '.ods': new_filename += '.ods' if dst_path is None: # Необходимо определить результирующий путь dst_path = dlg.getDirDlg(self._ParentForm, u'Папка хранения') 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.getAskBox(u'Заменить существующий файл?'): shutil.copyfile(src_filename, dst_filename) else: shutil.copyfile(src_filename, dst_filename) cmd = OFFICE_OPEN_CMD_FORMAT % dst_filename log.debug(u'Command <%s>' % textfunc.toUnicode(cmd)) os.system(cmd) return True except: # Вывести сообщение об ошибке в лог log.fatal(u'New report template by LibreOffice Calc')
def Edit(self, RepFileName_=None): """ Редактирование отчета. @param RepFileName_: Полное имя файла шаблона отчета. """ # Создание связи с ActiveX rprt_file_name = os.path.abspath(RepFileName_) rep = ic_res.LoadResource(rprt_file_name) report_dir = os.path.abspath(ic.engine.ic_user.icGet('REPORT_DIR')) rep_file = os.path.abspath(rep['generator'], report_dir) reportman_designer_key = ic_util.GetRegValue('Software\\Classes\\Report Manager Designer\\shell\\open\\command', None) if reportman_designer_key: reportman_designer_run = reportman_designer_key.replace('\'%1\'', '\'%s\'') % rep_file cmd = 'start %s' % reportman_designer_run log.debug(u'Запуск команды ОС: <%s>' % cmd) # и запустить Report Manager Designer os.system(cmd) else: msg = u'Не определен дизайнер отчетов Report Manager Designer %s' % reportman_designer_key log.warning(msg) ic_dlg.icWarningBox(u'ВНИМАНИЕ!', msg) # Определить файл *.xml xml_file = os.path.normpath(os.path.abspath(os.path.splitext(RepFileName_)[0]+'.xml')) cmd = 'start excel.exe \'%s\'' % xml_file log.debug(u'Запуск команды ОС: <%s>' % cmd) # и запустить MSExcel os.system(cmd)
def _getPageSetup(self, PageSetup_): """ Определить параметры страницы. """ page_setup = {} # Ориентиция layouts = [obj for obj in PageSetup_['children'] if obj['name'] == 'Layout'] log.debug('Layout %s' % layouts) if layouts: layout = layouts[0] if 'Orientation' in layout: if layout['Orientation'] == 'Landscape': page_setup['orientation'] = icrepgen.IC_REP_ORIENTATION_LANDSCAPE elif layout['Orientation'] == 'Portrait': page_setup['orientation'] = icrepgen.IC_REP_ORIENTATION_PORTRAIT # Начало нумерации страниц if 'StartPageNumber' in layout: page_setup['start_num'] = int(layout['StartPageNumber']) # Поля page_margins = [obj for obj in PageSetup_['children'] if obj['name'] == 'PageMargins'] log.debug('PageMargins %s' % page_margins) if page_margins: page_margin = page_margins[0] page_setup['page_margins'] = [] page_setup['page_margins'].append(float(page_margin.get('Left', 0))) page_setup['page_margins'].append(float(page_margin.get('Right', 0))) page_setup['page_margins'].append(float(page_margin.get('Top', 0))) page_setup['page_margins'].append(float(page_margin.get('Bottom', 0))) page_setup['page_margins'] = tuple(page_setup['page_margins']) return page_setup
def glue_pdf_files(out_pdf_filename, *pdf_filenames): """ Процедура склеивания/объединения PDf файлов в один. @param out_pdf_filename: Полное наименование результирующего PDF файла. @param pdf_filenames: Список имен файлов-источников. Объединение происходит в порядке указанном списком pdf_filenames. Если какой либо файл отсутствует, то объединение происходит без него. @return: True - объединение прошло успешно / False - ошибка по какой-либо причине. """ try: merger = PyPDF2.PdfFileMerger() filenames = [ filename for filename in pdf_filenames if filename.lower().endswith('.pdf') and os.path.exists(filename) ] for filename in filenames: pdf_file = open(filename, 'rb') log.debug(u'Объединение PDF файла <%s> => <%s>' % (filename, out_pdf_filename)) reader = PyPDF2.PdfFileReader(pdf_file) merger.append(reader) out_pdf_filename = os.path.abspath(out_pdf_filename) if os.path.exists(out_pdf_filename): log.info(u'Удаление файла <%s>' % out_pdf_filename) try: os.remove(out_pdf_filename) except: log.fatal(u'Ошибка удаления файла <%s>' % out_pdf_filename) log.debug(u'Запись результирующего файла <%s>' % out_pdf_filename) merger.write(out_pdf_filename) return True except: log.fatal(u'Ошибка склеивания/объединения PDF файлов') return False
def get_current_dir(): """ Текущая папка. Относительнай путь считается от папки defis. @return: """ cur_dir = os.path.dirname(os.path.dirname(ic.config.__file__)) log.debug(u'Текущая папка определена как <%s>' % cur_dir) return cur_dir
def scan_pack(self, scan_filenames=()): """ Сканировать документы в пакетном режиме и сохранить их в файлы. @param scan_filenames: Имена файлов скана с указанием количества листов и признаком 2-стороннего сканирования. Например: ('D:/tmp/scan001', 3, True), ('D:/tmp/scan002', 1, False), ('D:/tmp/scn003', 2, True), ... @return: Список имен файлов скана. None - в случае ошибки. """ result = list() # Счетчик отсканированных листов tray_sheet_count = 0 # Объем лотка в листах max_sheets = self.getMaxSheets() # В пакетном режиме не используем диалоговое окно # Но в случае режима склеивания документа по частям диалоговые окна используются # Объект приложения для управления диалоговыми окнами wx_app = None for scan_filename, n_pages, is_duplex in scan_filenames: tray_sheet_count += n_pages if not is_duplex else n_pages/2 if tray_sheet_count <= max_sheets: # Пока счетчик сканирования не превысил ограничение объема лотка, # то продолжаем обычное сканирование scan_result = self.scan_pack_part(scan_filename, n_pages, is_duplex) result.append(scan_filename if scan_result and os.path.exists(scan_filename) else None) else: log.debug(u'Включение режима сканирования документа <%s> по частям. Количество страниц [%d] Текущий счетчик %d. ' % (scan_filename, n_pages, tray_sheet_count)) if wx_app is None: # Внимание! Приложение создается для # управления диалоговыми окнами wx_app = wx.PySimpleApp() # ВНИМАНИЕ! Выставить русскую локаль # Это необходимо для корректного отображения календарей, # форматов дат, времени, данных и т.п. locale = wx.Locale() locale.Init(wx.LANGUAGE_RUSSIAN) # Если в лотке кончилась бумага, то надо запустить процедуру склейки последнего # документа glue_result = self.scan_glue(scan_filename, n_pages, is_duplex) # М.б. нажата <Отмена> или какая то ошибка result.append(scan_filename if glue_result and os.path.exists(scan_filename) else None) # ВНИМАНИЕ! После успешно отсканированного большого документа # сбрасываем счетчик отсканированных листов tray_sheet_count = 0 # ВНИМАНИЕ! Т.к. взаимодействие построено на модальных диалоговых # окнах, то MainLoop делать не надо иначе основное приложение зависает # if wx_app: # wx_app.MainLoop() return result
def Update(self, RepTemplateFileName_=None): """ Обновить шаблон отчета в системе генератора отчетов. @param RepTemplateFileName_: Имя файла шаблона отчета. Если None, то должен производиться запрос на выбор этого файла. @return: Имя файла файла шаблона или None в случае ошибки. """ if RepTemplateFileName_ is None: filename = dlg.getFileDlg( self._ParentForm, u'Выберите шаблон отчета:', u'Microsoft Excel 2003 XML (*.xml)|*.xml|Электронные таблицы ODF (*.ods)|*.ods', self.getReportDir()) else: filename = os.path.abspath(os.path.normpath(RepTemplateFileName_)) if os.path.isfile(filename): # Конвертация log.debug(u'Начало конвертации <%s>' % filename) tmpl_filename = None template = None if os.path.exists( os.path.splitext(filename)[0] + DEFAULT_TEMPLATE_EXT): tmpl_filename = os.path.splitext( filename)[0] + DEFAULT_TEMPLATE_EXT template = icreptemplate.icODSReportTemplate() elif os.path.exists( os.path.splitext(filename)[0] + ODS_TEMPLATE_EXT): tmpl_filename = os.path.splitext( filename)[0] + ODS_TEMPLATE_EXT template = icreptemplate.icODSReportTemplate() elif os.path.exists( os.path.splitext(filename)[0] + XLS_TEMPLATE_EXT): tmpl_filename = os.path.splitext( filename)[0] + XLS_TEMPLATE_EXT template = icreptemplate.icXLSReportTemplate() elif os.path.exists( os.path.splitext(filename)[0] + XML_TEMPLATE_EXT): tmpl_filename = os.path.splitext( filename)[0] + XML_TEMPLATE_EXT template = icreptemplate.icExcelXMLReportTemplate() else: log.warning(u'Not find report template for <%s>' % filename) if template: rep_template = template.read(tmpl_filename) new_filename = os.path.splitext( filename)[0] + DEFAULT_REPORT_TEMPLATE_EXT res.saveResourcePickle(new_filename, rep_template) log.info(u'Конец конвертации') return new_filename else: log.warning(u'Не найден файл источника шаблона <%s>' % filename) return None
def _execQueryFunc(self, Query_, vars=None): """ Получить запрос из функции. @param Query_: Текст запроса. @param vars: Внешние переменные. @return: Возвращает запрос в разрешенном формате. """ # Убрать сигнатуру определения функции func = Query_.replace(PY_SIGNATURE, '').strip() var_names = vars.keys() if vars else None log.debug(u'Выполнение функции: <%s>. Дополнительные переменные %s' % (func, var_names)) return execfunc.exec_code(func, name_space=locals(), kwargs=vars)
def OnPreviewRepButton(self, event): """ Обработчик нажатия кнопки 'Предварительный просмотр/Печать'. """ # Определить выбранный пункт дерева item = self.rep_tree.GetSelection() item_data = self.rep_tree.GetPyData(item) log.debug(u'Preview <%s>' % item_data[REP_FILE_IDX]) # Если это файл отчета, то получить его if item_data is not None and item_data[REP_ITEMS_IDX] is None: # Получение отчета report_generator.getReportGeneratorSystem(item_data[REP_FILE_IDX], ParentForm_=self, bRefresh=True).Preview() # Если это папка, то вывести сообщение else: dlg.getMsgBox(u'Необходимо выбрать отчет!', parent=self)
def OnConvertRepButton(self, event): """ Обработчик нажатия кнопки 'Конвертация'. """ # Определить выбранный пункт дерева item = self.rep_tree.GetSelection() item_data = self.rep_tree.GetPyData(item) log.debug(u'Convert <%s>' % item_data[REP_FILE_IDX]) # Если это файл отчета, то получить его if item_data is not None and item_data[REP_ITEMS_IDX] is None: # Получение отчета report_generator.getReportGeneratorSystem(item_data[REP_FILE_IDX], ParentForm_=self, bRefresh=True).Convert() else: dlg.getMsgBox(u'Необходимо выбрать отчет!', parent=self) event.Skip()
def scanSingle(self, scan_filename=None): """ Одностраничное сканирование Если вкл. ДУПЛЕКС и выключено многостраничное сканирование, то надо отсканировать 1 лист с 2-х сторон. @param scan_filename: Имя файла скана. Если имя файла не указано, то происходит сканирование и возвращается объект PIL.Image. @return: True - все прошло успешно. False - ошибка. """ if self.isDuplexOption(): # Если вкл. ДУПЛЕКС и выключено многостраничное сканирование, # то надо отсканировать 1 лист с 2-х сторон log.debug(u'Сканирование дуплекс') return self.scanMulti(scan_filename, 2) # Сканирование одной страницы log.debug(u'Одностороннее сканирование') self.startScan() scan_obj = self.scan(scan_filename) return scan_obj is not None
def view_file_ext(filename): """ Запуск просмотра файла внешней программой. Определение какой программой производить просмотр определяется по расширению файла. @param filename: Полное имя файла. @return: True/False. """ if not os.path.exists(filename): log.warning(u'Просмотр файла внешней программой. Файл <%s> не наден.' % filename) return False file_type = os.path.splitext(filename)[1] file_ext = file_type.lower() for file_extensions, view_cmd_associate in ASSOCIATION_VIEW_FILE.items(): if file_ext in file_extensions: cmd = view_cmd_associate % filename log.debug(u'Запуск комманды <%s>' % cmd) os.system(cmd) return True
def _genHeader(self, Header_): """ Сгенерировать заголовок отчета и перенести ее в выходной отчет. @param Header_: Бэнд заголовка. @return: Возвращает результат выполнения операции True/False. """ try: log.debug(u'Генерация заголовка') # Добавлять будем в конец отчета, # поэтому опреелить максимальную строчку 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 # Увеличить текущую координату Y self._cur_top += cur_height # Прописать область self._Rep['header'] = { 'row': max_row, 'col': Header_['col'], 'row_size': i_row, 'col_size': Header_['col_size'], } # Очистить сумы суммирующих ячеек self._TemplateSheet = self._clearSum(self._TemplateSheet, 0, len(self._TemplateSheet)) return True except: # Вывести сообщение об ошибке в лог log.fatal(u'Ошибка генерации заголовка отчета <%s>.' % textfunc.toUnicode(self._RepName)) return False
def OnUpdateRepButton(self, event): """ Обработчик нажатия кнопки 'Обновление отчета'. """ # Определить выбранный пункт дерева item = self.rep_tree.GetSelection() item_data = self.rep_tree.GetPyData(item) # Если это файл отчета, то запустить обновление шаблона if item_data is not None and item_data[REP_ITEMS_IDX] is None: # Запустить обновление шаблона отчета log.debug('Update <%s> report' % item_data[0]) report_generator.getReportGeneratorSystem(item_data[REP_FILE_IDX], ParentForm_=self).Update( item_data[0]) else: report_generator.getCurReportGeneratorSystem(self).Update() # Заполнить дерево отчетов self._fillReportTree(self._ReportDir) event.Skip()
def _getFontStyle(self, style): """ Взять описание шрифта из стиля. @param style: Описание стиля. """ # Шрифт описанный в стиле style_font = [style_attr for style_attr in style['children'] if style_attr['name'] == 'Font'] log.debug('Font <%s> Style <%s>' % (style_font, style['ID'])) if style_font: style_font = style_font[0] else: style_font = {} # Выходная структура шрифта font = {'name': 'Arial Cyr', 'size': 10, 'family': 'default', 'faceName': None, 'underline': False, 'style': 'regular', } if 'FontName' in style_font: font['name'] = style_font['FontName'] font['faceName'] = style_font['FontName'] if 'Size' in style_font: font['size'] = float(style_font['Size']) if 'Underline' in style_font: font['underline'] = True if 'Bold' in style_font and style_font['Bold'] == '1': style = 'bold' if 'Italic' in style_font and style_font['Italic'] == '1': style = 'boldItalic' font['style'] = style elif 'Italic' in style_font and style_font['Italic'] == '1': font['style'] = 'italic' return font
def runScan(self): """ Запусть процесс сканирования, согласно выставленным параметрам. @return: True/False """ if self.scan_manager is None: log.warning(u'Не определен менеджер сканирования') return False if self.scanner is None: log.warning(u'Не определено устройство сканирования') return False self.scan_manager.init() self.scan_manager.open(self.scanner) # Выставить все опции options = dict() if self.scan_source: options['source'] = self.scan_source if self.scan_mode: options['mode'] = self.scan_mode if self.depth: options['depth'] = self.depth if self.page_size: options['page_width'] = self.page_size[0] options['page_height'] = self.page_size[1] else: # ВНИМАНИЕ! Если не определить размер страницы # край скана будет обрезаться # По умолчанию A4 портретной ориентации options['page_width'] = 210.0 options['page_height'] = 297.0 if self.scan_area: options['tl_x'] = self.scan_area[0] options['tl_y'] = self.scan_area[1] if self.scan_area and self.page_size: options['br_x'] = self.page_size[0] - self.scan_area[2] options['br_y'] = self.page_size[1] - self.scan_area[3] else: # ВНИМАНИЕ! Если не определить размер страницы # край скана будет обрезаться # По умолчанию A4 портретной ориентации options['br_x'] = 210.0 options['br_y'] = 297.0 self.scan_manager.setScanOptions(**options) # Определение имени файла сканирования scan_filename = os.path.join( ic_file.getHomeDir(), config.PROFILE_DIRNAME, self.scan_filename + '.' + self.scan_filetype ) if self.scan_filename else config.DEFAULT_SCAN_FILENAME if os.path.exists(scan_filename): # Удалить старый файл сканирования try: os.remove(scan_filename) log.info(u'Удален файл <%s>' % scan_filename) except OSError: log.fatal(u'Ошибка удаления файла <%s>' % scan_filename) log.debug(u'Сканирование в файл <%s>' % scan_filename) try: if not self.is_multi_scan: result = self.scan_manager.singleScan(scan_filename) else: result = self.scan_manager.multiScan(scan_filename) if not result: # Какая-то ошибка сканирования dlg.getErrBox( u'ОШИБКА', u'Ошибка сканирования. Проверте листы в лотке сканера') return False if self.scan_dir: self.copyToScanDir(scan_filename, self.scan_dir) if self.is_preview: self.previewScanFile(scan_filename) return True except: log.fatal(u'Ошибка сканирования') return False
def loadResourceFile(filename, dictRpl={}, bRefresh=False, *arg, **kwarg): """ Загрузить ресурс из файла. Функция читает файл и выполняет его. @type filename: C{string} @param filename: Имя ресурсного файла. @type dictRpl: C{dictionary} @param dictRpl: Словарь замен. @type bRefresh: C{bool} @param bRefresh: Признак того, что файл надо перечитать даже если он буферезирован. """ obj = None filename = filename.strip() try: # Проверяем есть ли в буфферном файле такой объект, если есть, то его и возвращаем if not bRefresh and filename in Buff_readAndEvalFile: log.debug(' ' * 3 + '[b] ' + 'Return from buffer file: <%s>' % filename) return Buff_readAndEvalFile[filename] nm = os.path.basename(filename) pt = nm.find('.') if pt >= 0: filepcl = os.path.dirname( filename) + '/' + nm[:pt] + '_pkl' + nm[pt:] else: filepcl = os.path.dirname(filename) + '/' + nm + '_pkl' # Проверяем нужно ли компилировать данную структуру по следующим признакам: # наличие скомпилированного файла, по времени последней модификации. try: if (os.path.isfile(filepcl) and not os.path.isfile(filename)) or \ (os.path.getmtime(filename) < os.path.getmtime(filepcl)): # Пытаеся прочитать сохраненную структуру если время последней # модификации текстового представления меньше, времени # последней модификации транслированного варианта. fpcl = None try: fpcl = open(filepcl) obj = cPickle.load(fpcl) fpcl.close() # Сохраняем объект в буфере Buff_readAndEvalFile[filename] = obj log.debug(' [+] Load from: %s' % filepcl) return obj except IOError: log.error(' [-] readAndEvalFile: Open file <%s> error.' % filepcl) except: if fpcl: fpcl.close() except: pass # Пытаемся прочитать cPickle, если не удается считаем, что в файле # хранится текст. Читаем его, выполняем, полученный объект сохраняем # на диске для последующего использования if os.path.isfile(filename): try: fpcl = open(filename) obj = cPickle.load(fpcl) fpcl.close() # Сохраняем объект в буфере Buff_readAndEvalFile[filename] = obj log.debug(' [+] Load file <%s> cPickle Format.' % filename) return obj except Exception, msg: log.error( ' [*] Non cPickle Format file <%s>. Try to compile text' % filename) # Открываем текстовое представление, если его нет, то создаем его f = open(filename, 'rb') txt = f.read().replace('\r\n', '\n') f.close() for key in dictRpl: txt = txt.replace(key, dictRpl[key]) # Выполняем obj = eval(txt) # Сохраняем объект в буфере Buff_readAndEvalFile[filename] = obj # Сохраняем транслированный вариант fpcl = open(filepcl, 'w') log.debug('Create cPickle <%s>' % filepcl) cPickle.dump(obj, fpcl, PICKLE_PROTOCOL) fpcl.close()
def _defBand(self, BandTag_, Row_, ColCount_, TitleRow_, Rep_): """ Заполнить описание бенда. @param BandTag_: Тег бэнда. @param Row_: Номер строки. @param TitleRow_: Количество строк заголовочных бендов. @param ColCount_: Количество колонок. @param Rep_: Описание данных отчета. @return: Описание данных отчета. """ try: # Сделать копию данных отчета для возможного отката. rep = copy.deepcopy(Rep_) log.debug(u'Определение бэнда. Тег: <%s>' % BandTag_) if BandTag_.strip() == HEADER_TAG: # Заполнить бэнд rep['header'] = self._band(rep['header'], Row_-TitleRow_, ColCount_) elif BandTag_.strip() == DETAIL_TAG: # Заполнить бэнд rep['detail'] = self._band(rep['detail'], Row_-TitleRow_, ColCount_) self._normDetail(rep['detail'], rep) elif BandTag_.strip() == FOOTER_TAG: # Заполнить бэнд rep['footer'] = self._band(rep['footer'], Row_-TitleRow_, ColCount_) elif HEADER_GROUP_TAG in BandTag_: # Определить имя поля группировки field_name = re.split(icrepgen.REP_FIELD_PATT, BandTag_)[1].strip()[2:-2] # Если такой группы не зарегестрировано, то прописать ее if reduce(lambda x, grp: grp['field'] == field_name or x, rep['groups'], 0) == 0: # Записать в соответствии с положением относительно др. групп rep['groups'].append(copy.deepcopy(icrepgen.IC_REP_GRP)) rep['groups'][-1]['field'] = field_name # Записать заголовок группы grp_field = [grp for grp in rep['groups'] if grp['field'] == field_name][0] # Заполнить бэнд grp_field['header'] = self._band(grp_field['header'], Row_-TitleRow_, ColCount_) elif FOOTER_GROUP_TAG in BandTag_: # Определить имя поля группировки field_name = re.split(icrepgen.REP_FIELD_PATT, BandTag_)[1].strip()[2:-2] # Если такой группы не зарегестрировано, то прописать ее if reduce(lambda x, grp: grp['field'] == field_name or x, rep['groups'], 0) == 0: # Записать в соответствии с положением относительно др. групп rep['groups'].append(copy.deepcopy(icrepgen.IC_REP_GRP)) rep['groups'][-1]['field'] = field_name # Записать примечание группы grp_field = [grp for grp in rep['groups'] if grp['field'] == field_name][0] # Заполнить бэнд grp_field['footer'] = self._band(grp_field['footer'], Row_-TitleRow_, ColCount_) elif BandTag_.strip() == UPPER_TAG: # Верхний колонтитул rep['upper'] = self._band(rep['upper'], Row_-TitleRow_, ColCount_) elif BandTag_.strip() == UNDER_TAG: # Нижний колонтитул rep['under'] = self._band(rep['under'], Row_-TitleRow_, ColCount_) else: # Вывести сообщение об ошибке в лог log.warning(u'Не определенный тип бэнда <%s>.' % BandTag_) # Заполнить колонтитулы rep['upper'] = self._bandUpper(rep['upper'], self._rep_worksheet) rep['under'] = self._bandUnder(rep['under'], self._rep_worksheet) return rep except: log.fatal(u'Ошибка определения бэнда <%s>.' % BandTag_) return Rep_
def parse(self, TemplateData_, template_name=None): """ Разобрать/преобразовать прочитанную структуру. @param TemplateData_: Словарь описания шаблона. @param template_name: Имя шаблона(листа), если None то первый лист. """ try: # Создать первоначальный шаблон rep = copy.deepcopy(icrepgen.IC_REP_TMPL) # 0. Определение основных структур workbook = TemplateData_['children'][0] # Стили (в виде словаря) styles = dict([(style['ID'], style) for style in [element for element in workbook['children'] if element['name'] == 'Styles'][0]['children']]) worksheets = [element for element in workbook['children'] if element['name'] == 'Worksheet'] # I. Определить все бэнды в шаблоне # Если имя шаблона не определено, тогда взять первый лист if template_name is None: template_name = worksheets[0]['Name'] self._rep_worksheet = worksheets[0] else: # Установить активной страницу выбранного шаблона отчета self._rep_worksheet = [sheet for sheet in worksheets if sheet['Name'] == template_name][0] # Прописать имя отчета rep['name'] = template_name # Взять таблицу rep_template_tabs = [rep_obj for rep_obj in self._rep_worksheet['children'] if rep_obj['name'] == 'Table'] self._setDefaultCellSize(rep_template_tabs[0]) # Привести таблицу к нормальному виду rep_template_tab = self._normTable(rep_template_tabs[0]) # Взять описания колонок rep_template_cols = [element for element in rep_template_tab['children'] if element['name'] == 'Column'] rep_template_cols = self._defineSpan(rep_template_cols) # Взять описания строк rep_template_rows = [element for element in rep_template_tab['children'] if element['name'] == 'Row'] rep_template_rows = self._defineSpan(rep_template_rows) # Количество колонок без колонки тегов бендов col_count = self._getColumnCount(rep_template_rows) log.debug(u'Количество колонок: %d' % col_count) # II. Определить все ячейки листа used_rows = range(len(rep_template_rows)) used_cols = range(col_count) self.__cur_band = None # Тег текущего бенда # Перебор по строкам for cur_row in used_rows: if not self._isTitleBand(rep_template_rows, cur_row): # Не колонтитулы, добавить ячейки в общий лист rep['sheet'].append([]) for cur_col in used_cols: cell_attr = self._getCellAttr(rep_template_rows, rep_template_cols, styles, cur_row, cur_col) if not self._isTag(cell_attr['value']): rep['sheet'][-1].append(cell_attr) else: rep['sheet'][-1].append(None) # III. Определить бэнды в шаблоне # Перебрать все ячейки первой колонки self.__cur_band = None # Тег текущего бенда title_row = 0 # Счетчик строк колонтитулов/заголовочных бендов # Перебор всех строк в шаблоне for cur_row in range(len(rep_template_rows)): tag = self._getTagBandRow(rep_template_rows, cur_row) # Если это ячейка с определенным тегом, значит новый бенд if tag: # Определить текущий бэнд self.__cur_band = tag if tag in TITLE_TAGS: # Обработка строк заголовочных тегов parse_func = self._TitleTagParse.setdefault(tag, None) try: parse_func(self, rep, rep_template_rows[cur_row]['children']) except: log.fatal(u'Ошибка парсинга функции <%s>' % textfunc.toUnicode(parse_func)) title_row += 1 else: # Определить бэнд внутри объекта rep = self._defBand(self.__cur_band, cur_row, col_count, title_row, rep) else: log.error(u'Не корректный тег строки [%d]' % cur_row) # Прочитать в шаблон параметры страницы rep['page_setup'] = copy.deepcopy(icrepgen.IC_REP_PAGESETUP) sheet_options = [rep_obj for rep_obj in self._rep_worksheet['children'] if rep_obj['name'] == 'WorksheetOptions'] page_setup = [rep_obj for rep_obj in sheet_options[0]['children'] if rep_obj['name'] == 'PageSetup'][0] rep['page_setup'].update(self._getPageSetup(page_setup)) print_setup = [rep_obj for rep_obj in sheet_options[0]['children'] if rep_obj['name'] == 'Print'] if print_setup: rep['page_setup'].update(self._getPrintSetup(print_setup[0])) # Проверить заполнение генератора отчета if not rep['generator']: tmpl_filename = self.getTemplateFilename() rep['generator'] = os.path.splitext(tmpl_filename)[1].upper() if tmpl_filename else '.ODS' return rep except: log.fatal(u'Ошибка парсинга шаблона отчета <%s>' % textfunc.toUnicode(template_name)) return None
def scan_glue_mode(scan_manager, scan_filename, n_sheets, is_duplex=False, max_tray_sheets=60): """ Запуск режима склеивания документа по частям. @param scan_manager: Менеджер сканирования. @param scan_filename: Имя результирующего файла скана. @param n_sheets: Количество листов. @param is_duplex: Двустороннее сканирование? @param max_tray_sheets: Максимально допустимое количество листов в лотке сканера. @return: True/False. """ # Основной цикл сканирования документа по частям и последующая склейка n_part = 1 scan_file_path, scan_file_ext = os.path.splitext(scan_filename) part_suffix = '_part%03d' % n_part new_scan_filename = scan_file_path + part_suffix + scan_file_ext sheets = scan_glue_load_sheets(None, min(max_tray_sheets, n_sheets)) scan_sheet_count = sheets is_cancel = scan_sheet_count <= 0 while (0 < scan_sheet_count <= n_sheets) or is_cancel: log.debug(u'Сканирование файла <%s> Сканировать листов [%d]' % (new_scan_filename, sheets)) # Если используется дуплекс, то надо увеличить количество страниц scan_n_pages = sheets * 2 if is_duplex else sheets # Запуск процесса сканирования scan_result = scan_manager.scanMulti(new_scan_filename, scan_n_pages) if scan_result and os.path.exists(new_scan_filename): verify_result = scan_glue_verify(None, new_scan_filename) if verify_result: n_part += 1 part_suffix = '_part%03d' % n_part new_scan_filename = scan_file_path + part_suffix + scan_file_ext do_scan_sheet_count = min(max_tray_sheets, n_sheets - scan_sheet_count) if do_scan_sheet_count <= 0: # Все листы отсканированны break sheets = scan_glue_load_sheets(None, do_scan_sheet_count) if sheets <= 0: # Нажата <Отмена> is_cancel = True break scan_sheet_count += sheets elif verify_result is None: scan_sheet_count -= sheets sheets = scan_glue_load_sheets(None, min(max_tray_sheets, n_sheets)) if sheets <= 0: # Нажата <Отмена> is_cancel = True break scan_sheet_count += sheets else: is_cancel = True log.warning(u'Сканирование по частям файла <%s> отменено' % new_scan_filename) break else: is_cancel = True log.warning(u'Ошибка сканирования файла <%s>' % new_scan_filename) # Склеить отсканированные части документа if not is_cancel: part_pdf_filenames = [ scan_file_path + ('_part%03d' % i_part) + scan_file_ext for i_part in range(1, n_part) ] log.debug(u'Объединение %d частей скана %s в PDF файл %s' % (n_part - 1, part_pdf_filenames, scan_filename)) glue_result = pdffunc.glue_pdf_files(scan_filename, *part_pdf_filenames) dlgfunc.getMsgBox( u'СКАНИРОВАНИЕ', u'Загрузите в лоток сканера документы для последующего сканирования' ) return glue_result else: log.warning( u'Режим объединения сканированного документа по частям отменен') return False
def generate(self, RepTemplate_, QueryTable_, NameSpace_=None, CoordFill_=None): """ Генерация отчета. @param RepTemplate_: Структура шаблона отчета (см. спецификации). @param QueryTable_: Таблица запроса. Словарь следующей структуры: { '__name__':имя таблицы запроса, '__fields__':[имена полей], '__data__':[список списков значений], '__sub__':{словарь данных подотчетов}, }. @param NameSpace_: Пространство имен шаблона. Обычный словарь: { 'имя переменной': значение переменной, }. ВНИМАНИЕ! Этот словарь может передаваться в таблице запроса ключ __variables__. @param CoordFill_: Координатное заполнение значений ячеек. Формат: { (Row,Col): 'Значение', }. ВНИМАНИЕ! Этот словарь может передаваться в таблице запроса ключ __coord_fill__. @return: Заполненную структуру отчета. """ try: # Покоординатная замена значений ячеек self._CoordFill = CoordFill_ if QueryTable_ and '__coord_fill__' in QueryTable_: if self._CoordFill is None: self._CoordFill = dict() self._CoordFill.update(QueryTable_['__coord_fill__']) # Инициализация списка групп self._RepGrp = list() # I. Определить все бэнды в шаблоне и ячейки сумм if isinstance(RepTemplate_, dict): self._Template = RepTemplate_ else: # Вывести сообщение об ошибке в лог log.warning(u'Ошибка типа шаблона отчета <%s>.' % type(RepTemplate_)) return None # Инициализация имени отчета if 'name' in QueryTable_ and QueryTable_['name']: # Если таблица запроса именована, то значит это имя готового отчета self._RepName = str(QueryTable_['name']) elif 'name' in self._Template: self._RepName = self._Template['name'] # Заполнить пространство имен self._NameSpace = NameSpace_ if self._NameSpace is None: self._NameSpace = dict() self._NameSpace.update(self._Template['variables']) if QueryTable_ and '__variables__' in QueryTable_: self._NameSpace.update(QueryTable_['__variables__']) log.debug(u'Переменные отчета: %s' % self._NameSpace.keys()) # Библиотека стилей self._StyleLib = None if 'style_lib' in self._Template: self._StyleLib = self._Template['style_lib'] self._TemplateSheet = self._Template['sheet'] self._TemplateSheet = self._initSumCells(self._TemplateSheet) # II. Инициализация таблицы запроса self._QueryTbl = QueryTable_ # Определить количество записей в таблице запроса self._QueryTblRecCount = 0 if self._QueryTbl and '__data__' in self._QueryTbl: self._QueryTblRecCount = len(self._QueryTbl['__data__']) # Проинициализировать бенды групп for grp in self._Template['groups']: grp['old_rec'] = None time_start = time.time() log.info(u'Отчет <%s>. Запуск генерации' % textfunc.toUnicode(self._RepName)) # III. Вывод данных в отчет # Создать отчет self._Rep = copy.deepcopy(IC_REP_TMPL) self._Rep['name'] = self._RepName # Инициализация необходимых переменных field_idx = {} # Индексы полей i = 0 i_rec = 0 # Перебор полей таблицы запроса if self._QueryTbl and '__fields__' in self._QueryTbl: for cur_field in self._QueryTbl['__fields__']: field_idx[cur_field] = i i += 1 # Если записи в таблице запроса есть, то ... if self._QueryTblRecCount: # Проинициализировать текущую строку для использования # ее в заголовке отчета rec = self._QueryTbl['__data__'][i_rec] # Заполнить словарь текущей записи for field_name in field_idx.keys(): val = rec[field_idx[field_name]] # Предгенерация значения данных ячейки self._CurRec[field_name] = val # Прописать индекс текущей записи self._CurRec['ic_sys_num_rec'] = i_rec # Верхний колонтитул if self._Template['upper']: self._genUpper(self._Template['upper']) # Вывести в отчет заголовок self._genHeader(self._Template['header']) # Главный цикл # Перебор записей таблицы запроса while i_rec < self._QueryTblRecCount: # Обработка групп # Проверка смены группы в описании всех групп # и найти индекс самой общей смененной группы i_grp_out = -1 # индекс самой общей смененной группы # Флаг начала генерации (примечания групп не выводяться) start_gen = False for i_grp in range(len(self._Template['groups'])): grp = self._Template['groups'][i_grp] if grp['old_rec']: # Проверить условие вывода примечания группы if self._CurRec[grp['field']] != grp['old_rec'][ grp['field']]: i_grp_out = i_grp break else: i_grp_out = 0 start_gen = True break if i_grp_out != -1: # Вывести примечания if start_gen is False: for i_grp in range( len(self._Template['groups']) - 1, i_grp_out - 1, -1): grp = self._Template['groups'][i_grp] self._genGrpFooter(grp) # Вывести заголовки for i_grp in range(i_grp_out, len(self._Template['groups'])): grp = self._Template['groups'][i_grp] grp['old_rec'] = copy.deepcopy(self._CurRec) self._genGrpHeader(grp) # Область данных self._genDetail(self._Template['detail']) # Увеличить суммы суммирующих ячеек self._sumIterate(self._TemplateSheet, self._CurRec) # Перейти на следующую запись i_rec += 1 # Заполнить словарь текущей записи if i_rec < self._QueryTblRecCount: rec = self._QueryTbl['__data__'][i_rec] # Заполнить словарь текущей записи for field_name in field_idx.keys(): val = rec[field_idx[field_name]] # Предгенерация значения данных ячейки self._CurRec[field_name] = val # Прописать индекс текущей записи self._CurRec['ic_sys_num_rec'] = i_rec # Вывести примечания после области данных for i_grp in range(len(self._Template['groups']) - 1, -1, -1): grp = self._Template['groups'][i_grp] if grp['old_rec']: self._genGrpFooter(grp) else: break # Вывести в отчет примечание отчета self._genFooter(self._Template['footer']) # Нижний колонтитул if self._Template['under']: self._genUnder(self._Template['under']) # Параметры страницы self._Rep['page_setup'] = self._Template['page_setup'] # Прогресс бар log.info( u'Отчет <%s>. Окончание генерации. Время: %d сек.' % (textfunc.toUnicode(self._RepName), time.time() - time_start)) return self._Rep except: # Вывести сообщение об ошибке в лог log.fatal(u'Ошибка генерации отчета.') return None
def showOptions(self): """ Выставить параметры сканирования в контролах окна. """ if self.scanner: self.scanner_comboBox.SetStringSelection(self.scanner) if self.scan_source: i = 0 try: log.debug(u'Установка источника сканирования <%s>' % self.scan_source) i = scan_manager.SCAN_SOURCES.index(self.scan_source) except ValueError: log.warning(u'Не найден источник сканирования <%s>' % self.scan_source) self.source_comboBox.Select(i) if self.scan_mode: i = 0 try: i = scan_manager.SCAN_MODES.index(self.scan_mode) except ValueError: log.warning(u'Не найден режим сканирования <%s>' % self.scan_mode) self.mode_comboBox.Select(i) self.multiscan_checkBox.SetValue(bool(self.is_multi_scan)) self.preview_checkBox.SetValue(bool(self.is_preview)) if self.page_size: i = 0 try: i = scan_manager.SCAN_PAGE_SIZES.index(self.page_size) except ValueError: log.warning(u'Не найден размер страницы сканирования <%s>' % self.page_size) self.pagesize_comboBox.Select(i) if self.scan_area: self.left_spinCtrl.SetValue(self.scan_area[0]) self.top_spinCtrl.SetValue(self.scan_area[1]) self.right_spinCtrl.SetValue(self.scan_area[2]) self.bottom_spinCtrl.SetValue(self.scan_area[3]) if self.scan_dir: self.scan_dirPicker.SetPath(self.scan_dir) if self.scan_filename: self.filename_textCtrl.SetValue(self.scan_filename) if self.scan_filetype: i = 0 try: i = scan_manager.SCAN_FILE_TYPES.index(self.scan_filetype) except ValueError: log.warning(u'Не найден тип файла сканирования <%s>' % self.scan_filetype) self.fileext_comboBox.Select(i) if self.depth: self.depth_spinCtrl.SetValue(self.depth) if self.ext_scan_cmd: self.extern_cmd_textCtrl.SetValue(self.ext_scan_cmd)
def _genTxt(self, cell, record=None, CellRow_=None, CellCol_=None): """ Генерация текста. @param cell: Ячейка. @param record: Словарь, описывающий текущую запись таблицы запроса. Формат: { <имя поля> : <значение поля>, ...} @param CellRow_: Номер строки ячейки в результирующем отчете. @param CellCol_: Номер колонки ячейки в результирующем отчете. @return: Возвращает сгенерированное значение. """ try: # Проверка на преобразование типов cell_val = cell['value'] if cell_val is not None and type(cell_val) not in (str, unicode): cell_val = str(cell_val) if cell_val not in self._cellFmt: parsed_fmt = self.funcStrParse(cell_val) self._cellFmt[cell_val] = parsed_fmt else: parsed_fmt = self._cellFmt[cell_val] func_str = [] # Выходной список значений i_sum = 0 # Перебрать строки функционала for cur_func in parsed_fmt['func']: # Функция if re.search(REP_FUNC_PATT, cur_func): value = str(self._execFuncGen(cur_func[2:-2], locals())) # Ламбда-выражение elif re.search(REP_LAMBDA_PATT, cur_func): # ВНИМАНИЕ: Лямбда-выражение в шаблоне должно иметь # 1 аргумент это словарь записи. # Например: # [~rec: rec['name']=='Петров'~] lambda_func = eval('lambda ' + cur_func[2:-2]) value = str(lambda_func(record)) # Переменная elif re.search(REP_VAR_PATT, cur_func): var_name = cur_func[2:-2] if var_name in self._NameSpace: log.debug(u'Обработка переменной <%s>' % var_name) else: log.warning( u'Переменная <%s> не найдена в пространстве имен' % var_name) value = str(self._NameSpace.setdefault(var_name, u'')) # Блок кода elif re.search(REP_EXEC_PATT, cur_func): # ВНИМАНИЕ: В блоке кода доступны объекты cell и record. # Если надо вывести информацию, то ее надо выводить в # переменную value. # Например: # [=if record['name']=='Петров': # value='-'=] value = '' exec_func = cur_func[2:-2].strip() try: exec exec_func except: log.fatal(u'Ошибка выполнения блока кода <%s>' % textfunc.toUnicode(exec_func)) # Системная функция elif re.search(REP_SYS_PATT, cur_func): # Функция суммирования if cur_func[2:6].lower() == 'sum(': value = str(cell['sum'][i_sum]['value']) i_sum += 1 # Перейти к следующей сумме # Функция вычисления среднего значения elif cur_func[2:6].lower() == 'avg(': if 'ic_sys_num_rec' not in record: record['ic_sys_num_rec'] = 0 value = str(cell['sum'][i_sum]['value'] / (record['ic_sys_num_rec'] + 1)) i_sum += 1 # Перейти к следующей сумме elif cur_func[2:-2].lower() == 'n': if 'ic_sys_num_rec' not in record: record['ic_sys_num_rec'] = 0 sys_num_rec = record['ic_sys_num_rec'] value = str(sys_num_rec + 1) else: # Вывести сообщение об ошибке в лог log.warning( u'Неизвестная системная функция <%s> шаблона <%s>.' % (textfunc.toUnicode(cur_func), self._RepName)) value = '' # Стиль elif re.search(REP_STYLE_PATT, cur_func): value = '' style_name = cur_func[2:-2] self._setStyleAttr(style_name) # Под-отчеты elif re.search(REP_SUBREPORT_PATT, cur_func): value = '' subreport_name = cur_func[2:-2] self._genSubReport(subreport_name, CellRow_) # Поле elif re.search(REP_FIELD_PATT, cur_func): field_name = str((cur_func[2:-2])) try: value = record[field_name] except KeyError: log.warning(u'В строке (%s) поле <%s> не найдено' % (textfunc.toUnicode(record), textfunc.toUnicode(field_name))) value = '' # ВНИМАНИЕ! В значении ячейки тоже могут быть управляющие коды value = self._genTxt({'value': value}, record) func_str.append(value) # Заполнение формата return self._valueFormat(parsed_fmt['fmt'], func_str) except: # Вывести сообщение об ошибке в лог log.fatal(u'Ошибка генерации текста ячейки <%s> шаблона <%s>.' % (textfunc.toUnicode(cell['value']), self._RepName)) return None
def main(argv): """ Основная запускающая функция. @param argv: Список параметров коммандной строки. """ # Инициализоция системы журналирования log.init(config) # Разбираем аргументы командной строки try: options, args = getopt.getopt(argv, 'h?vdVEDpPES', [ 'help', 'version', 'debug', 'log', 'viewer', 'editor', 'postprint', 'postpreview', 'postexport', 'print=', 'preview=', 'export=', 'select=', 'gen=', 'db=', 'sql=', 'stylelib=', 'var=', 'path=', 'no_gui' ]) except getopt.error as err: log.error(err.msg, bForcePrint=True) log.warning('For help use --help option', bForcePrint=True) sys.exit(2) # Параметры запуска генерации отчета из коммандной строки report_filename = None db = None sql = None do_cmd = None stylelib = None vars = dict() path = None mode = 'default' mode_arg = None for option, arg in options: if option in ('-h', '--help', '-?'): print(__doc__) sys.exit(0) elif option in ('-v', '--version'): print('icReport version: %s' % '.'.join([str(ver) for ver in __version__])) sys.exit(0) elif option in ('-d', '--debug'): config.set_glob_var('DEBUG_MODE', True) elif option in ('-l', '--log'): config.set_glob_var('LOG_MODE', True) elif option in ('-V', '--viewer'): mode = 'view' elif option in ('-E', '--editor'): mode = 'edit' elif option in ('-p', '--print'): mode = 'print' mode_arg = arg elif option in ('-P', '--preview'): mode = 'preview' mode_arg = arg elif option in ('-E', '--export'): mode = 'export' mode_arg = arg elif option in ('-S', '--select'): mode = 'select' mode_arg = arg elif option in ('--gen', ): report_filename = arg elif option in ('--db', ): db = arg elif option in ('--sql', ): sql = arg elif option in ('--postprint', ): do_cmd = do_report.DO_COMMAND_PRINT elif option in ('--postpreview', ): do_cmd = do_report.DO_COMMAND_PREVIEW elif option in ('--postexport', ): do_cmd = do_report.DO_COMMAND_EXPORT elif option in ('--stylelib', ): stylelib = arg elif option in ('--var', ): var_name = arg.split('=')[0].strip() var_value = arg.split('=')[-1].strip() vars[var_name] = var_value log.debug(u'Дополнительная переменная <%s>. Значение [%s]' % (unicode(var_name, config.DEFAULT_ENCODING), unicode(var_value, config.DEFAULT_ENCODING))) elif option in ('--path', ): path = arg elif option in ('--no_gui', ): config.set_glob_var('NO_GUI_MODE', True) # ВНИМАНИЕ! Небходимо добавить путь к папке отчетов, # чтобы проходили импорты модулей отчетов if path is None: path = DEFAULT_REPORTS_PATH if os.path.exists(path) and os.path.isdir(path) and path not in sys.path: sys.path.append(path) # Внимание! Приложение создается для # управления диалоговыми окнами отчетов app = wx.PySimpleApp() # ВНИМАНИЕ! Выставить русскую локаль # Это необходимо для корректного отображения календарей, # форматов дат, времени, данных и т.п. locale = wx.Locale() locale.Init(wx.LANGUAGE_RUSSIAN) if mode == 'default': if report_filename: # Запустить генерацию отчета из комадной строки do_report.doReport(report_filename=report_filename, report_dir=path, db_url=db, sql=sql, command=do_cmd, stylelib_filename=stylelib, variables=vars) elif mode == 'view': do_report.ReportViewer(report_dir=path) elif mode == 'edit': do_report.ReportEditor(report_dir=path) elif mode == 'print': do_report.ReportPrint(report_filename=mode_arg, report_dir=path, db_url=db, sql=sql, command=do_cmd, stylelib_filename=stylelib, variables=vars) elif mode == 'preview': do_report.ReportPreview(report_filename=mode_arg, report_dir=path, db_url=db, sql=sql, command=do_cmd, stylelib_filename=stylelib, variables=vars) elif mode == 'export': do_report.ReportExport(report_filename=mode_arg, report_dir=path, db_url=db, sql=sql, command=do_cmd, stylelib_filename=stylelib, variables=vars) elif mode == 'select': do_report.ReportSelect(report_filename=mode_arg, report_dir=path, db_url=db, sql=sql, command=do_cmd, stylelib_filename=stylelib, variables=vars) app.MainLoop()
def runScanPack(self, *scan_filenames): """ Запусть процесс сканирования в режиме пакетной обработки, согласно выставленным параметрам. @param scan_filenames: Имена файлов скана с указанием количества листов и признака 2-стороннего сканирования. Например: (scan001, 3, True), (scan002, 1, False), (scn003, 2, True), ... @return: True/False """ if self.scan_manager is None: log.warning(u'Не определен менеджер сканирования') return False if self.scanner is None: log.warning(u'Не определено устройство сканирования') return False self.scan_manager.init() self.scan_manager.open(self.scanner) # Выставить все опции options = dict() if self.scan_source: options['source'] = self.scan_source if self.scan_mode: options['mode'] = self.scan_mode if self.depth: options['depth'] = self.depth if self.page_size: options['page_width'] = self.page_size[0] options['page_height'] = self.page_size[1] else: # ВНИМАНИЕ! Если не определить размер страницы # край скана будет обрезаться # По умолчанию A4 портретной ориентации options['page_width'] = 210.0 options['page_height'] = 297.0 if self.scan_area: options['tl_x'] = self.scan_area[0] options['tl_y'] = self.scan_area[1] if self.scan_area and self.page_size: options['br_x'] = self.page_size[0] - self.scan_area[2] options['br_y'] = self.page_size[1] - self.scan_area[3] else: # ВНИМАНИЕ! Если не определить размер страницы # край скана будет обрезаться # По умолчанию A4 портретной ориентации options['br_x'] = 210.0 options['br_y'] = 297.0 self.scan_manager.setScanOptions(**options) scans = [(os.path.join(ic_file.getHomeDir(), config.PROFILE_DIRNAME, scan_filename + '.' + self.scan_filetype) if scan_filename else config.DEFAULT_SCAN_FILENAME, int(n_pages), bool(is_duplex)) for scan_filename, n_pages, is_duplex in scan_filenames] for scan_filename, n_pages, is_duplex in scans: full_scan_filename = os.path.join( os.environ.get('HOME', '/home/user'), config.PROFILE_DIRNAME, scan_filename) if os.path.exists(full_scan_filename): # Удалить старый файл сканирования try: os.remove(full_scan_filename) log.info(u'Удален ранее отсканированный файл <%s>' % full_scan_filename) except OSError: log.fatal(u'Ошибка удаления файла <%s>' % full_scan_filename) try: scan_filenames = self.scan_manager.scan_pack(scan_filenames=scans) # Перенос отсканированных файлов в результирующую папку if self.scan_dir and os.path.exists(self.scan_dir): for scan_filename in scan_filenames: if scan_filename and os.path.exists(scan_filename): log.debug( u'Перенос файла <%s> в результирующую папку <%s>' % (scan_filename, self.scan_dir)) self.copyToScanDir(scan_filename, self.scan_dir) else: log.warning( u'Не определен результирующий файл сканирования') else: log.warning(u'Не определена результирующая папка сканирования') return True except: log.fatal(u'Ошибка сканирования в режиме пакетной обработки') return False