def test_edit(): mimetypes = [ 'application/x-latex', 'application/x-tex', 'text/latex', 'text/tex', 'text/plain' ] for mimetype in mimetypes: editor_cmd = get_editor_cmd(mimetype, filename) if editor_cmd is not None: break if editor_cmd is None: # LaTeX code is text: also consider text *viewers* # since pretty much any of them will be an editor as well for mimetype in mimetypes: editor_cmd = get_viewer_cmd(mimetype, filename) if editor_cmd is not None: break if editor_cmd is None: return False result = gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = True) return result
def _on_mail_items_button_pressed(self, event): event.Skip() items = self._LCTRL_items.get_selected_item_data(only_one=False) if len(items) == 0: return True found, external_cmd = gmShellAPI.detect_external_binary('gm-mail_doc') if not found: return False files2mail = [] for item in items: files2mail.append(item.save_to_file()) cmd = '%s %s' % (external_cmd, ' '.join(files2mail)) if os.name == 'nt': blocking = True else: blocking = False success = gmShellAPI.run_command_in_shell(command=cmd, blocking=blocking) if not success: gmGuiHelpers.gm_show_error(aMessage=_('Error mailing documents.'), aTitle=_('Mailing documents')) return False self.save_soap_note(soap=_('Mailed:\n - %s') % '\n - '.join([i['description'] for i in items])) return True
def test_edit(): mimetypes = [ 'application/x-latex', 'application/x-tex', 'text/latex', 'text/tex', 'text/plain' ] for mimetype in mimetypes: editor_cmd = get_editor_cmd(mimetype, filename) if editor_cmd is not None: break if editor_cmd is None: # LaTeX code is text: also consider text *viewers* # since pretty much any of them will be an editor as well for mimetype in mimetypes: editor_cmd = get_viewer_cmd(mimetype, filename) if editor_cmd is not None: break if editor_cmd is None: return False result = gmShellAPI.run_command_in_shell(command=editor_cmd, blocking=True) return result
def acquire_pages_into_files(self, delay=None, filename=None): """Call XSane. <filename> name part must have format name-001.ext> """ if filename is None: filename = gmTools.get_unique_filename(prefix = 'gm-scan-') name, ext = os.path.splitext(filename) filename = '%s-001%s' % (name, cXSaneScanner._FILETYPE) filename = os.path.abspath(os.path.expanduser(filename)) cmd = 'xsane --no-mode-selection --save --force-filename "%s" --xsane-rc "%s" %s %s' % ( filename, self.__get_session_xsanerc(), gmTools.coalesce(self.device_settings_file, '', '--device-settings %s'), gmTools.coalesce(self.default_device, '') ) normal_exit = gmShellAPI.run_command_in_shell(command = cmd, blocking = True) if normal_exit: flist = glob.glob(filename.replace('001', '*')) flist.sort() return flist raise OSError(-1, 'error running XSane as [%s]' % cmd)
def _on_burn_items_button_pressed(self, event): event.Skip() found, external_cmd = gmShellAPI.detect_external_binary('gm-burn_doc') if not found: return False items = self._LCTRL_items.get_selected_item_data(only_one=False) if len(items) == 0: items = self._LCTRL_items.get_item_data() base_dir = None dlg = wx.DirDialog( self, message=_( 'If you wish to include an existing directory select it here:' ), defaultPath=os.path.join(gmTools.gmPaths().home_dir, 'gnumed'), style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST) choice = dlg.ShowModal() path2include = dlg.GetPath() if choice == wx.ID_OK: if not gmTools.dir_is_empty(path2include): base_dir = path2include export_dir = gmPerson.gmCurrentPatient().export_area.export( base_dir=base_dir, items=items, with_metadata=True) if export_dir is None: return False cmd = u'%s %s' % (external_cmd, export_dir) if os.name == 'nt': blocking = True else: blocking = False success = gmShellAPI.run_command_in_shell(command=cmd, blocking=blocking) if not success: gmGuiHelpers.gm_show_error( aMessage=_('Error burning documents to CD/DVD.'), aTitle=_('Burning documents')) return False self.save_soap_note(soap=_('Burned onto CD/DVD:\n - %s') % u'\n - '.join([i['description'] for i in items])) browse_index = gmGuiHelpers.gm_show_question( title=title, question=_('Browse patient data pack ?'), cancel_button=False) if browse_index: gmNetworkTools.open_url_in_browser( url=u'file://%s' % os.path.join(export_dir, u'index.html')) return True
def get_data_source_version(self, force_reload=False): if self.__data_date is not None: if not force_reload: return { 'data': self.__data_date, 'online_update': self.__online_update_date } try: open(self.data_date_filename, 'wb').close() except Exception: _log.error('problem querying the MMI drug database for version information') _log.exception('cannot create MMI drug database version file [%s]', self.data_date_filename) self.__data_date = None self.__online_update_date = None return { 'data': '?', 'online_update': '?' } cmd = '%s -DATADATE' % self.path_to_binary if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True): _log.error('problem querying the MMI drug database for version information') self.__data_date = None self.__online_update_date = None return { 'data': '?', 'online_update': '?' } try: version_file = io.open(self.data_date_filename, mode = 'rt', encoding = 'utf8') except Exception: _log.error('problem querying the MMI drug database for version information') _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename) self.__data_date = None self.__online_update_date = None return { 'data': '?', 'online_update': '?' } self.__data_date = version_file.readline()[:10] self.__online_update_date = version_file.readline()[:10] version_file.close() return { 'data': self.__data_date, 'online_update': self.__online_update_date }
def mixin_insert_unicode_character(self): # if cUnicodeInsertion_TextCtrlMixin._unicode_selector is None: if __UNICODE_SELECTOR_APP is None: return False # read clipboard if wx.TheClipboard.IsOpened(): _log.error('clipboard already open') return False if not wx.TheClipboard.Open(): _log.error('cannot open clipboard') return False data_obj = wx.TextDataObject() prev_clip = None got_it = wx.TheClipboard.GetData(data_obj) if got_it: prev_clip = data_obj.Text # run selector #if not gmShellAPI.run_command_in_shell(command = cUnicodeInsertion_TextCtrlMixin._unicode_selector, blocking = True): if not gmShellAPI.run_command_in_shell(command=__UNICODE_SELECTOR_APP, blocking=True): wx.TheClipboard.Close() return False # read clipboard again got_it = wx.TheClipboard.GetData(data_obj) wx.TheClipboard.Close() if not got_it: _log.debug('clipboard does not contain text') return False curr_clip = data_obj.Text # insert clip if any if curr_clip == prev_clip: # nothing put into clipboard (that is, clipboard still the same) return False self.WriteText(curr_clip) return True
def switch_to_frontend(self, blocking=False, cmd=None): try: # must make sure csv file exists open(self.default_csv_filename, 'wb').close() except IOError: _log.exception('problem creating GL/MMI <-> GNUmed exchange file') return False if cmd is None: cmd = ('%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg if os.name == 'nt': blocking = True if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): _log.error('problem switching to the MMI drug database') # apparently on the first call MMI does not # consistently return 0 on success # return False return True
def _on_fax_items_button_pressed(self, event): event.Skip() items = self._LCTRL_items.get_selected_item_data(only_one=False) if len(items) == 0: return found, external_cmd = gmShellAPI.detect_external_binary('gm-fax_doc') if not found: return False files2fax = [] for item in items: files2fax.append(item.save_to_file()) fax_number = wx.GetTextFromUser(_( 'Please enter the fax number here !\n\n' 'It can be left empty if the external\n' 'fax software knows how to get the number.'), caption=_('Faxing documents'), parent=self, centre=True) cmd = '%s "%s" %s' % (external_cmd, fax_number, ' '.join(files2fax)) if os.name == 'nt': blocking = True else: blocking = False success = gmShellAPI.run_command_in_shell(command=cmd, blocking=blocking) if not success: gmGuiHelpers.gm_show_error( aMessage=_('Error faxing documents to\n\n %s') % fax_number, aTitle=_('Faxing documents')) return False self.save_soap_note( soap=_('Faxed to [%s]:\n - %s') % (fax_number, '\n - '.join([i['description'] for i in items]))) return True
def mixin_insert_unicode_character(self): if cUnicodeInsertion_TextCtrlMixin._unicode_selector is None: return False # read clipboard if wx.TheClipboard.IsOpened(): _log.error('clipboard already open') return False if not wx.TheClipboard.Open(): _log.error('cannot open clipboard') return False data_obj = wx.TextDataObject() prev_clip = None got_it = wx.TheClipboard.GetData(data_obj) if got_it: prev_clip = data_obj.Text # run selector if not gmShellAPI.run_command_in_shell(command = cUnicodeInsertion_TextCtrlMixin._unicode_selector, blocking = True): wx.TheClipboard.Close() return False # read clipboard again got_it = wx.TheClipboard.GetData(data_obj) wx.TheClipboard.Close() if not got_it: _log.debug('clipboard does not contain text') return False curr_clip = data_obj.Text # insert clip if so if curr_clip == prev_clip: # nothing put into clipboard (that is, clipboard still the same) return False self.WriteText(curr_clip) return True
def switch_to_frontend(self, blocking=False, mode='interactions'): """http://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html""" _log.debug('calling FreeDiams in [%s] mode', mode) self.__imported_drugs = [] if not self.__detect_binary(): return False self.__create_gm2fd_file(mode = mode) args = '--exchange-in="%s"' % (self.__gm2fd_filename) cmd = r'%s %s' % (self.path_to_binary, args) if os.name == 'nt': blocking = True if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): _log.error('problem switching to the FreeDiams drug database') return False if blocking == True: self.import_fd2gm_file_as_drugs() return True
def switch_to_frontend(self, blocking=False, mode='interactions'): """https://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html""" _log.debug('calling FreeDiams in [%s] mode', mode) self.__imported_drugs = [] if not self.__detect_binary(): return False self.__create_gm2fd_file(mode = mode) args = '--exchange-in="%s"' % (self.__gm2fd_filename) cmd = r'%s %s' % (self.path_to_binary, args) if os.name == 'nt': blocking = True if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): _log.error('problem switching to the FreeDiams drug database') return False if blocking == True: self.import_fd2gm_file_as_drugs() return True
def edit_visual_progress_note(filename=None, episode=None, discard_unmodified=False, doc_part=None, health_issue=None): """This assumes <filename> contains an image which can be handled by the configured image editor.""" if doc_part is not None: filename = doc_part.save_to_file() if filename is None: gmDispatcher.send( signal='statustext', msg=_('Cannot export visual progress note to file.')) return None editor = gmCfgDB.get4user( option='external.tools.visual_soap_editor_cmd', workplace=gmPraxis.gmCurrentPraxisBranch().active_workplace) if editor is None: _log.error( 'no editor for visual progress notes configured, trying mimetype editor' ) gmDispatcher.send( signal='statustext', msg=_('Editor for visual progress note not configured.'), beep=False) mimetype = gmMimeLib.guess_mimetype(filename=filename) editor = gmMimeLib.get_editor_cmd(mimetype=mimetype, filename=filename) if editor is None: _log.error( 'no editor for mimetype <%s> configured, trying mimetype viewer', mimetype) success, msg = gmMimeLib.call_viewer_on_file(aFile=filename, block=True) if not success: _log.debug('problem running mimetype <%s> viewer', mimetype) gmGuiHelpers.gm_show_error( _('There is no editor for visual progress notes defined.\n' 'Also, there is no editor command defined for the file type\n' '\n' ' [%s].\n' '\n' 'Therefor GNUmed attempted to at least *show* this\n' 'visual progress note. That failed as well, however:\n' '\n' '%s') % (mimetype, msg), _('Editing visual progress note')) editor = configure_visual_progress_note_editor() if editor is None: gmDispatcher.send( signal='statustext', msg=_( 'Editor for visual progress note not configured.'), beep=True) return None if '%(img)s' in editor: editor = editor % {'img': filename} else: editor = '%s %s' % (editor, filename) if discard_unmodified: original_stat = os.stat(filename) original_md5 = gmTools.file2md5(filename) success = gmShellAPI.run_command_in_shell(editor, blocking=True) if not success: success, msg = gmMimeLib.call_viewer_on_file(aFile=filename, block=True) if not success: _log.debug('problem running mimetype <%s> viewer', mimetype) gmGuiHelpers.gm_show_error( _('There was a problem running the editor\n' '\n' ' [%s] (%s)\n' '\n' 'on the visual progress note.\n' '\n' 'Therefor GNUmed attempted to at least *show* it.\n' 'That failed as well, however:\n' '\n' '%s') % (editor, mimetype, msg), _('Editing visual progress note')) editor = configure_visual_progress_note_editor() if editor is None: gmDispatcher.send( signal='statustext', msg=_('Editor for visual progress note not configured.'), beep=True) return None try: open(filename, 'r').close() except Exception: _log.exception('problem accessing visual progress note file [%s]', filename) gmGuiHelpers.gm_show_error( _('There was a problem reading the visual\n' 'progress note from the file:\n' '\n' ' [%s]\n' '\n') % filename, _('Saving visual progress note')) return None if discard_unmodified: modified_stat = os.stat(filename) # same size ? if original_stat.st_size == modified_stat.st_size: modified_md5 = gmTools.file2md5(filename) # same hash ? if original_md5 == modified_md5: _log.debug('visual progress note (template) not modified') # ask user to decide msg = _( 'You either created a visual progress note from a template\n' 'in the database (rather than from a file on disk) or you\n' 'edited an existing visual progress note.\n' '\n' 'The template/original was not modified at all, however.\n' '\n' 'Do you still want to save the unmodified image as a\n' 'visual progress note into the EMR of the patient ?\n') save_unmodified = gmGuiHelpers.gm_show_question( msg, _('Saving visual progress note')) if not save_unmodified: _log.debug('user discarded unmodified note') return if doc_part is not None: _log.debug('updating visual progress note') doc_part.update_data_from_file(fname=filename) doc_part.set_reviewed(technically_abnormal=False, clinically_relevant=True) return None if not isinstance(episode, gmEMRStructItems.cEpisode): if episode is None: episode = _('visual progress notes') pat = gmPerson.gmCurrentPatient() emr = pat.emr episode = emr.add_episode(episode_name=episode.strip(), pk_health_issue=health_issue, is_open=False) doc = gmDocumentWidgets.save_file_as_new_document( filename=filename, document_type=gmDocuments.DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE, episode=episode, unlock_patient=False, pk_org_unit=gmPraxis.gmCurrentPraxisBranch()['pk_org_unit'], date_generated=gmDateTime.pydt_now_here()) doc.set_reviewed(technically_abnormal=False, clinically_relevant=True) return doc
def _on_burn_items_button_pressed(self, event): event.Skip() # anything to do ? found, external_cmd = gmShellAPI.detect_external_binary('gm-burn_doc') if not found: return items = self._LCTRL_items.get_selected_item_data(only_one=False) if len(items) == 0: items = self._LCTRL_items.get_item_data() if len(items) == 0: return pat = gmPerson.gmCurrentPatient() dlg = cCreatePatientMediaDlg(self, -1, burn2cd=True, patient=pat, item_count=len(items)) choice = dlg.ShowModal() if choice != wx.ID_SAVE: return path2include = dlg._LBL_directory.Label.strip() include_selected_dir = dlg._CHBOX_include_directory.IsChecked() dlg.Destroy() # do the export base_dir = None if include_selected_dir: if gmTools.dir_is_empty(path2include) is False: base_dir = gmTools.get_unique_filename(suffix='.iso') try: shutil.copytree(path2include, base_dir) except shutil.Error: _log.exception( 'cannot copy include directory [%s] -> [%s]', path2include, base_dir) return export_dir = gmPerson.gmCurrentPatient().export_area.export( base_dir=base_dir, items=items, with_metadata=True) if export_dir is None: return # burn onto media cmd = '%s %s' % (external_cmd, export_dir) if os.name == 'nt': blocking = True else: blocking = False success = gmShellAPI.run_command_in_shell(command=cmd, blocking=blocking) if not success: gmGuiHelpers.gm_show_error( aMessage=_('Error burning documents to CD/DVD.'), aTitle=_('Burning documents')) return self.save_soap_note(soap=_('Burned onto CD/DVD:\n - %s') % '\n - '.join([i['description'] for i in items])) browse_index = gmGuiHelpers.gm_show_question( title=_('Creating patient media'), question=_('Browse patient data pack ?'), cancel_button=False) if browse_index: gmNetworkTools.open_url_in_browser( url='file://%s' % os.path.join(export_dir, 'index.html')) return True
def call_editor_on_file(filename=None, block=True): """Try to find an appropriate editor with all tricks and call it. block: try to detach from editor or not, None means to use mailcap default. """ if not os.path.isdir(filename): # is the file accessible at all ? try: open(filename).close() except Exception: _log.exception('cannot read [%s]', filename) msg = _('[%s] is not a readable file') % filename return False, msg mime_type = guess_mimetype(filename) editor_cmd = get_editor_cmd(mime_type, filename) if editor_cmd is not None: if gmShellAPI.run_command_in_shell(command=editor_cmd, blocking=block): return True, '' viewer_cmd = get_viewer_cmd(mime_type, filename) if viewer_cmd is not None: if gmShellAPI.run_command_in_shell(command=viewer_cmd, blocking=block): return True, '' _log.warning("no editor or viewer found via standard mailcap system") if os.name == "posix": _log.warning( "you should add an editor and/or viewer for this mime type to your mailcap file" ) _log.info("let's see what the OS can do about that") # does the file already have a useful extension ? (path_name, f_ext) = os.path.splitext(filename) if f_ext in ['', '.tmp']: # try to guess one f_ext = guess_ext_by_mimetype(mime_type) if f_ext is None: _log.warning("no suitable file extension found, trying anyway") file_to_display = filename f_ext = '?unknown?' else: file_to_display = filename + f_ext shutil.copyfile(filename, file_to_display) else: file_to_display = filename file_to_display = os.path.normpath(file_to_display) _log.debug("file %s <type %s> (ext %s) -> file %s" % (filename, mime_type, f_ext, file_to_display)) # try to detect any of the UNIX openers (will only find viewers) found, startfile_cmd = _get_system_startfile_cmd(filename) if found: if gmShellAPI.run_command_in_shell(command=startfile_cmd, blocking=block): return True, '' # last resort: hand over to Python itself try: os.startfile(file_to_display) return True, '' except AttributeError: _log.exception('os.startfile() does not exist on this platform') except Exception: _log.exception('os.startfile(%s) failed', file_to_display) msg = _("Unable to edit/view the file:\n\n" " [%s]\n\n" "Your system does not seem to have a (working)\n" "editor or viewer registered for the file type\n" " [%s]") % (file_to_display, mime_type) return False, msg
def edit_visual_progress_note(filename=None, episode=None, discard_unmodified=False, doc_part=None, health_issue=None): """This assumes <filename> contains an image which can be handled by the configured image editor.""" if doc_part is not None: filename = doc_part.export_to_file() if filename is None: gmDispatcher.send( signal=u'statustext', msg=_('Cannot export visual progress note to file.')) return None dbcfg = gmCfg.cCfgSQL() cmd = dbcfg.get2( option=u'external.tools.visual_soap_editor_cmd', workplace=gmPraxis.gmCurrentPraxisBranch().active_workplace, bias='user') if cmd is None: gmDispatcher.send( signal=u'statustext', msg=_('Editor for visual progress note not configured.'), beep=False) cmd = configure_visual_progress_note_editor() if cmd is None: gmDispatcher.send( signal=u'statustext', msg=_('Editor for visual progress note not configured.'), beep=True) return None if u'%(img)s' in cmd: cmd = cmd % {u'img': filename} else: cmd = u'%s %s' % (cmd, filename) if discard_unmodified: original_stat = os.stat(filename) original_md5 = gmTools.file2md5(filename) success = gmShellAPI.run_command_in_shell(cmd, blocking=True) if not success: gmGuiHelpers.gm_show_error( _('There was a problem with running the editor\n' 'for visual progress notes.\n' '\n' ' [%s]\n' '\n') % cmd, _('Editing visual progress note')) return None try: open(filename, 'r').close() except Exception: _log.exception('problem accessing visual progress note file [%s]', filename) gmGuiHelpers.gm_show_error( _('There was a problem reading the visual\n' 'progress note from the file:\n' '\n' ' [%s]\n' '\n') % filename, _('Saving visual progress note')) return None if discard_unmodified: modified_stat = os.stat(filename) # same size ? if original_stat.st_size == modified_stat.st_size: modified_md5 = gmTools.file2md5(filename) # same hash ? if original_md5 == modified_md5: _log.debug('visual progress note (template) not modified') # ask user to decide msg = _( u'You either created a visual progress note from a template\n' u'in the database (rather than from a file on disk) or you\n' u'edited an existing visual progress note.\n' u'\n' u'The template/original was not modified at all, however.\n' u'\n' u'Do you still want to save the unmodified image as a\n' u'visual progress note into the EMR of the patient ?\n') save_unmodified = gmGuiHelpers.gm_show_question( msg, _('Saving visual progress note')) if not save_unmodified: _log.debug('user discarded unmodified note') return if doc_part is not None: _log.debug('updating visual progress note') doc_part.update_data_from_file(fname=filename) doc_part.set_reviewed(technically_abnormal=False, clinically_relevant=True) return None if not isinstance(episode, gmEMRStructItems.cEpisode): if episode is None: episode = _('visual progress notes') pat = gmPerson.gmCurrentPatient() emr = pat.emr episode = emr.add_episode(episode_name=episode.strip(), pk_health_issue=health_issue, is_open=False) doc = gmDocumentWidgets.save_file_as_new_document( filename=filename, document_type=gmDocuments.DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE, episode=episode, unlock_patient=False, pk_org_unit=gmPraxis.gmCurrentPraxisBranch()['pk_org_unit']) doc.set_reviewed(technically_abnormal=False, clinically_relevant=True) return doc
def call_editor_on_file(filename=None, block=True): """Try to find an appropriate editor with all tricks and call it. block: try to detach from editor or not, None means to use mailcap default. """ if not os.path.isdir(filename): # is the file accessible at all ? try: open(filename).close() except: _log.exception('cannot read [%s]', filename) msg = _('[%s] is not a readable file') % filename return False, msg mime_type = guess_mimetype(filename) editor_cmd = get_editor_cmd(mime_type, filename) if editor_cmd is not None: if gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = block): return True, '' viewer_cmd = get_viewer_cmd(mime_type, filename) if viewer_cmd is not None: if gmShellAPI.run_command_in_shell(command = viewer_cmd, blocking = block): return True, '' _log.warning("no editor or viewer found via standard mailcap system") if os.name == "posix": _log.warning("you should add an editor and/or viewer for this mime type to your mailcap file") _log.info("let's see what the OS can do about that") # does the file already have a useful extension ? (path_name, f_ext) = os.path.splitext(filename) if f_ext in ['', '.tmp']: # try to guess one f_ext = guess_ext_by_mimetype(mime_type) if f_ext is None: _log.warning("no suitable file extension found, trying anyway") file_to_display = filename f_ext = '?unknown?' else: file_to_display = filename + f_ext shutil.copyfile(filename, file_to_display) else: file_to_display = filename file_to_display = os.path.normpath(file_to_display) _log.debug("file %s <type %s> (ext %s) -> file %s" % (filename, mime_type, f_ext, file_to_display)) # try to detect any of the UNIX openers (will only find viewers) found, startfile_cmd = _get_system_startfile_cmd(filename) if found: if gmShellAPI.run_command_in_shell(command = startfile_cmd, blocking = block): return True, '' # last resort: hand over to Python itself try: os.startfile(file_to_display) return True, '' except AttributeError: _log.exception('os.startfile() does not exist on this platform') except Exception: _log.exception('os.startfile(%s) failed', file_to_display) msg = _("Unable to edit/view the file:\n\n" " [%s]\n\n" "Your system does not seem to have a (working)\n" "editor or viewer registered for the file type\n" " [%s]" ) % (file_to_display, mime_type) return False, msg