Пример #1
0
 def match_all_above_thresh(fac, threshold=None):
     'do matching and assign all above thresh'
     if threshold == None:
         # User ask
         dlg = QInputDialog()
         threshres = dlg.getText(
             None, 'Threshold Selector', 'Enter a matching threshold.\n' +
             'The system will query each chip and assign all matches above this thresh'
         )
         if not threshres[1]:
             logmsg('Cancelled all match')
             return
         try:
             threshold = float(str(threshres[0]))
         except ValueError:
             logerr('The threshold must be a number')
     qm = fac.hs.qm
     cm = fac.hs.cm
     nm = fac.hs.nm
     vm = fac.hs.vm
     # Get model ready
     vm.sample_train_set()
     fac.hs.ensure_model()
     # Do all queries
     for qcx in iter(cm.get_valid_cxs()):
         qcid = cm.cx2_cid[qcx]
         logmsg('Querying CID=' + str(qcid))
         query_name = cm.cx2_name(qcx)
         logdbg(str(qcx))
         logdbg(str(type(qcx)))
         cm.load_features(qcx)
         res = fac.hs.query(qcid)
         # Match only those above a thresh
         res.num_top_min = 0
         res.num_extra_return = 0
         res.top_thresh = threshold
         top_cx = res.top_cx()
         if len(top_cx) == 0:
             print('No matched for cid=' + str(qcid))
             continue
         top_names = cm.cx2_name(top_cx)
         all_names = np.append(top_names, [query_name])
         if all([nm.UNIDEN_NAME() == name for name in all_names]):
             # If all names haven't been identified, make a new one
             new_name = nm.get_new_name()
         else:
             # Rename to the most frequent non ____ name seen
             from collections import Counter
             name_freq = Counter(np.append(top_names,
                                           [query_name])).most_common()
             new_name = name_freq[0][0]
             if new_name == nm.UNIDEN_NAME():
                 new_name = name_freq[1][0]
         # Do renaming
         cm.rename_chip(qcx, new_name)
         for cx in top_cx:
             cm.rename_chip(cx, new_name)
     fac.hs.uim.populate_tables()
Пример #2
0
 def match_all_above_thresh(fac, threshold=None):
     'do matching and assign all above thresh'
     if threshold == None:
         # User ask
         dlg = QInputDialog()
         threshres = dlg.getText(None, 'Threshold Selector', 
                                 'Enter a matching threshold.\n'+
          'The system will query each chip and assign all matches above this thresh')
         if not threshres[1]:
             logmsg('Cancelled all match')
             return
         try:
             threshold = float(str(threshres[0]))
         except ValueError: 
             logerr('The threshold must be a number')
     qm = fac.hs.qm
     cm = fac.hs.cm
     nm = fac.hs.nm
     vm = fac.hs.vm
     # Get model ready
     vm.sample_train_set()
     fac.hs.ensure_model()
     # Do all queries
     for qcx in iter(cm.get_valid_cxs()):
         qcid = cm.cx2_cid[qcx]
         logmsg('Querying CID='+str(qcid))
         query_name = cm.cx2_name(qcx)
         logdbg(str(qcx))
         logdbg(str(type(qcx)))
         cm.load_features(qcx)
         res = fac.hs.query(qcid)
         # Match only those above a thresh
         res.num_top_min = 0
         res.num_extra_return = 0
         res.top_thresh = threshold
         top_cx = res.top_cx()
         if len(top_cx) == 0:
             print('No matched for cid='+str(qcid))
             continue
         top_names = cm.cx2_name(top_cx)
         all_names = np.append(top_names,[query_name])
         if all([nm.UNIDEN_NAME() == name for name in all_names]):
             # If all names haven't been identified, make a new one 
             new_name = nm.get_new_name()
         else:
             # Rename to the most frequent non ____ name seen
             from collections import Counter
             name_freq = Counter(np.append(top_names,[query_name])).most_common()
             new_name = name_freq[0][0] 
             if new_name == nm.UNIDEN_NAME():
                 new_name = name_freq[1][0]
         # Do renaming
         cm.rename_chip(qcx, new_name)
         for cx in top_cx:
             cm.rename_chip(cx, new_name)
     fac.hs.uim.populate_tables()
Пример #3
0
    def add_new_prop(fac, propname=None):
        'add a new property to keep track of'
        if propname is None:
            # User ask
            dlg = QInputDialog()
            textres = dlg.getText(None, 'New Metadata Property','What is the new property name? ')
            if not textres[1]:
                logmsg('Cancelled new property')
                return
            propname = str(textres[0])

        logmsg('Adding property '+propname)
        fac.hs.cm.add_user_prop(propname)
        fac.hs.uim.populate_tables()
Пример #4
0
    def add_new_prop(fac, propname=None):
        'add a new property to keep track of'
        if propname is None:
            # User ask
            dlg = QInputDialog()
            textres = dlg.getText(None, 'New Metadata Property',
                                  'What is the new property name? ')
            if not textres[1]:
                logmsg('Cancelled new property')
                return
            propname = str(textres[0])

        logmsg('Adding property ' + propname)
        fac.hs.cm.add_user_prop(propname)
        fac.hs.uim.populate_tables()
Пример #5
0
 def word_dialog(self, msg):
     response = QInputDialog.getText(self.top_level_window(), "Ledger Wallet Authentication", msg, QLineEdit.Password)
     if not response[1]:
         self.word = None
     else:
         self.word = str(response[0])
     self.done.set()
Пример #6
0
 def __init__(self, pa, parent):
     QDialog.__init__(self, parent)
     TE_Dialog.__init__(self)
     self.setupUi(self)
     opts = smtp_prefs().parse()
     self.test_func = parent.test_email_settings
     self.test_button.clicked.connect(self.test)
     self.from_.setText(unicode(self.from_.text())%opts.from_)
     if pa:
         self.to.setText(pa)
     if opts.relay_host:
         tmp_password=''
         if opts.relay_prompt:
             header=opts.relay_username+'@'+opts.relay_host
             tmp_password, ok = QInputDialog.getText(self,
                 header,
                 _('Password:'******''
             else:
                 conf = smtp_prefs()
                 conf.set('relay_password', hexlify(str(tmp_password).encode('utf-8')))
                 tmp_password='******'
         else:
             tmp_password=unhexlify(opts.relay_password).decode('utf-8')
         self.label.setText(_('Using: %(un)s:%(pw)s@%(host)s:%(port)s and %(enc)s encryption')%
                 dict(un=opts.relay_username, pw=tmp_password,
                     host=opts.relay_host, port=opts.relay_port, enc=opts.encryption))
Пример #7
0
 def auth_dialog(self):
     response = QInputDialog.getText(None, "Ledger Wallet Authentication", self.message, QLineEdit.Password)
     if not response[1]:
         self.response = None
     else:
         self.response = str(response[0])
     self.done.set()
 def makeNewList(self):
     listName, okay = QInputDialog.getText(QInputDialog(), self.objectName().capitalize() + " List Name",
                                           "New " + self.objectName().capitalize() + " List Name:",
                                           QLineEdit.Normal, "New " + self.objectName().capitalize() + " List")
     if okay and len(listName) > 0:
         if any([listName in lst for lst in self._rddtDataExtractor.subredditLists]):
             QMessageBox.information(QMessageBox(), "Data Extractor for reddit",
                                     "Duplicate subreddit list names not allowed.")
             return
         self._lstChooser.addItem(listName)
         self._lstChooser.setCurrentIndex(self._lstChooser.count() - 1)
         self._chooserDict[listName] = ListModel([], self._classToUse)
         self.chooseNewList(self._lstChooser.count() - 1)
         if self._rddtDataExtractor.defaultSubredditListName is None:  # becomes None if user deletes all subreddit lists
             self._rddtDataExtractor.defaultSubredditListName = listName
         self._gui.setUnsavedChanges(True)
Пример #9
0
 def ask_user(self):
     # Ask the user for a factor by which to multiply all font sizes
     factor, ok = QInputDialog.getDouble(
         self.gui, 'Enter a magnification factor', 'Allow font sizes in the book will be multiplied by the specified factor',
         value=2, min=0.1, max=4
     )
     if ok:
         # Ensure any in progress editing the user is doing is present in the container
         self.boss.commit_all_editors_to_container()
         try:
             self.magnify_fonts(factor)
         except Exception:
             # Something bad happened report the error to the user
             import traceback
             error_dialog(self.gui, _('Failed to magnify fonts'), _(
                 'Failed to magnify fonts, click "Show details" for more info'),
                 det_msg=traceback.format_exc(), show=True)
             # Revert to the saved restore point
             self.boss.revert_requested(self.boss.global_undo.previous_container)
         else:
             # Show the user what changes we have made, allowing her to
             # revert them if necessary
             self.boss.show_current_diff()
             # Update the editor UI to take into account all the changes we
             # have made
             self.boss.apply_container_update_to_gui()
 def edit_bookmark(self):
     indexes = self.bookmarks_table.selectionModel().selectedIndexes()
     if indexes != []:
         title, ok = QInputDialog.getText(self, _('Edit bookmark'), _('New title for bookmark:'), QLineEdit.Normal, self._model.data(indexes[0], Qt.DisplayRole).toString())
         title = QVariant(unicode(title).strip())
         if ok and title:
             self._model.setData(indexes[0], title, Qt.EditRole)
Пример #11
0
 def word_dialog(self, msg):
     response = QInputDialog.getText(self.top_level_window(), "Ledger Wallet Authentication", msg, QLineEdit.Password)
     if not response[1]:
         self.word = None
     else:
         self.word = str(response[0])
     self.done.set()
Пример #12
0
 def go_to_line_number(self):
     ed = self.gui.central.current_editor
     if ed is None or not ed.has_line_numbers:
         return
     num, ok = QInputDialog.getInt(self.gui, _('Enter line number'), ('Line number:'), ed.current_line, 1, max(100000, ed.number_of_lines))
     if ok:
         ed.current_line = num
Пример #13
0
 def rename_requested(self, name, location):
     loc = location.replace('/', os.sep)
     base = os.path.dirname(loc)
     newname, ok = QInputDialog.getText(self.gui, _('Rename') + ' ' + name,
             '<p>'+_('Choose a new name for the library <b>%s</b>. ')%name +
             '<p>'+_('Note that the actual library folder will be renamed.'),
             text=name)
     newname = sanitize_file_name_unicode(unicode(newname))
     if not ok or not newname or newname == name:
         return
     newloc = os.path.join(base, newname)
     if os.path.exists(newloc):
         return error_dialog(self.gui, _('Already exists'),
                 _('The folder %s already exists. Delete it first.') %
                 newloc, show=True)
     if (iswindows and len(newloc) >
             LibraryDatabase2.WINDOWS_LIBRARY_PATH_LIMIT):
         return error_dialog(self.gui, _('Too long'),
                 _('Path to library too long. Must be less than'
                 ' %d characters.')%LibraryDatabase2.WINDOWS_LIBRARY_PATH_LIMIT,
                 show=True)
     try:
         os.rename(loc, newloc)
     except:
         import traceback
         error_dialog(self.gui, _('Rename failed'),
                 _('Failed to rename the library at %s. '
             'The most common cause for this is if one of the files'
             ' in the library is open in another program.') % loc,
                 det_msg=traceback.format_exc(), show=True)
         return
     self.stats.rename(location, newloc)
     self.build_menus()
     self.gui.iactions['Copy To Library'].build_menus()
Пример #14
0
def grab_text_using_dialog(default="", title="title", label="label", iconPath="ui/border/MainWindow.png"):
    """
    Get some text from the user by putting up a dialog with the
    supplied title, label, and default text. Return (ok, text)
    as described below.

    Replace @@@ with \n in the returned text (and convert it to a Python
    string). If it contains unicode characters, raise UnicodeEncodeError.

    @return: the 2-tuple (ok, text), which is (True, text) if we succeed,
             or (False, None) if the user cancels.
    """
    # TODO: add an option to allow this to accept unicode,
    # and do something better if that's not provided and unicode is entered
    # (right now it just raises a UnicodeEncodeError).

    # modified from _set_test_from_dialog( ),
    # which was modified from debug_runpycode_from_a_dialog,
    # which does the "run py code" debug menu command

    # Qt4 version [070329; similar code in an exprs-module file]

    inputDialog = QDialog()  # No parent
    inputDialog.setWindowIcon(geticon(iconPath))

    text, ok = QInputDialog.getText(inputDialog, title, label, QLineEdit.Normal, default)
    # note: parent arg is needed in Qt4, not in Qt3

    if ok:
        # fyi: type(text) == <class '__main__.qt.QString'>
        text = str(text)
        text = text.replace("@@@", "\n")
    else:
        pass  # print "grab_text_using_dialog: cancelled"
    return ok, text
Пример #15
0
def debug_timing_test_pycode_from_a_dialog( ): #bruce 051117
    # TODO: rewrite this to call grab_text_using_dialog (should be easy)
    title = "debug: time python code"
    label = "one line of python to compile and exec REPEATEDLY in debug.py's globals()\n(or use @@@ to fake \\n for more lines)"
    from PyQt4.Qt import QInputDialog
    parent = None
    text, ok = QInputDialog.getText(parent, title, label) # parent argument needed only in Qt4 [bruce 070329, more info above]
    if not ok:
        print "time python code code: cancelled"
        return
    # fyi: type(text) == <class '__main__.qt.QString'>
    command = str(text)
    command = command.replace("@@@",'\n')
    print "trying to time the exec or eval of command:",command
    from code import compile_command
    try:
        try:
            mycode = compile( command + '\n', '<string>', 'exec') #k might need '\n\n' or '' or to be adaptive in length?
            # 'single' means print value if it's an expression and value is not None; for timing we don't want that so use 'eval'
            # or 'exec' -- but we don't know which one is correct! So try exec, if that fails try eval.
            print "exec" # this happens even for an expr like 2+2 -- why?
        except SyntaxError:
            print "try eval" # i didn't yet see this happen
            mycode = compile_command( command + '\n', '<string>', 'eval')
    except:
        print_compact_traceback("exception in compile_command: ")
        return
    if mycode is None:
        print "incomplete command:",command
        return
    # mycode is now a code object
    print_exec_timing_explored(mycode)
Пример #16
0
 def rename_genre(self):
     selected_genre = self.edit_table.get_selected_genre()
     if not selected_genre:
         return
     new_genre_name, ok = QInputDialog.getText(
         self,
         'Add new mapping',
         'Enter a CBDB genre name to create a mapping for:',
         text=selected_genre)
     if not ok:
         # Operation cancelled
         return
     new_genre_name = unicode(new_genre_name).strip()
     if not new_genre_name or new_genre_name == selected_genre:
         return
     data = self.edit_table.get_data()
     if new_genre_name.lower() != selected_genre.lower():
         # Verify it does not clash with any other mappings in the list
         for genre_name in data.keys():
             if genre_name.lower() == new_genre_name.lower():
                 return error_dialog(
                     self,
                     'Rename Failed',
                     'A genre with the same name already exists',
                     show=True)
     data[new_genre_name] = data[selected_genre]
     del data[selected_genre]
     self.edit_table.populate_table(data)
     self.edit_table.select_genre(new_genre_name)
Пример #17
0
def debug_timing_test_pycode_from_a_dialog( ): #bruce 051117
    # TODO: rewrite this to call grab_text_using_dialog (should be easy)
    title = "debug: time python code"
    label = "one line of python to compile and exec REPEATEDLY in debug.py's globals()\n(or use @@@ to fake \\n for more lines)"
    from PyQt4.Qt import QInputDialog
    parent = None
    text, ok = QInputDialog.getText(parent, title, label) # parent argument needed only in Qt4 [bruce 070329, more info above]
    if not ok:
        print "time python code code: cancelled"
        return
    # fyi: type(text) == <class '__main__.qt.QString'>
    command = str(text)
    command = command.replace("@@@",'\n')
    print "trying to time the exec or eval of command:",command
    from code import compile_command
    try:
        try:
            mycode = compile( command + '\n', '<string>', 'exec') #k might need '\n\n' or '' or to be adaptive in length?
            # 'single' means print value if it's an expression and value is not None; for timing we don't want that so use 'eval'
            # or 'exec' -- but we don't know which one is correct! So try exec, if that fails try eval.
            print "exec" # this happens even for an expr like 2+2 -- why?
        except SyntaxError:
            print "try eval" # i didn't yet see this happen
            mycode = compile_command( command + '\n', '<string>', 'eval')
    except:
        print_compact_traceback("exception in compile_command: ")
        return
    if mycode is None:
        print "incomplete command:",command
        return
    # mycode is now a code object
    print_exec_timing_explored(mycode)
Пример #18
0
    def s_r_save_query(self, *args):
        names = ['']
        names.extend(self.query_field_values)
        try:
            dex = names.index(self.saved_search_name)
        except:
            dex = 0
        name = ''
        while not name:
            name, ok = QInputDialog.getItem(self, _('Save search/replace'),
                                            _('Search/replace name:'), names,
                                            dex, True)
            if not ok:
                return
            if not name:
                error_dialog(self,
                             _("Save search/replace"),
                             _("You must provide a name."),
                             show=True)
        new = True
        name = unicode(name)
        if name in self.queries.keys():
            if not question_dialog(
                    self, _("Save search/replace"),
                    _("That saved search/replace already exists and will be overwritten. "
                      "Are you sure?")):
                return
            new = False

        query = {}
        query['name'] = name
        query['search_field'] = unicode(self.search_field.currentText())
        query['search_mode'] = unicode(self.search_mode.currentText())
        query['s_r_template'] = unicode(self.s_r_template.text())
        query['s_r_src_ident'] = unicode(self.s_r_src_ident.currentText())
        query['search_for'] = unicode(self.search_for.text())
        query['case_sensitive'] = self.case_sensitive.isChecked()
        query['replace_with'] = unicode(self.replace_with.text())
        query['replace_func'] = unicode(self.replace_func.currentText())
        query['destination_field'] = unicode(
            self.destination_field.currentText())
        query['s_r_dst_ident'] = unicode(self.s_r_dst_ident.text())
        query['replace_mode'] = unicode(self.replace_mode.currentText())
        query['comma_separated'] = self.comma_separated.isChecked()
        query['results_count'] = self.results_count.value()
        query['starting_from'] = self.starting_from.value()
        query['multiple_separator'] = unicode(self.multiple_separator.text())

        self.queries[name] = query
        self.queries.commit()

        if new:
            self.query_field.blockSignals(True)
            self.query_field.clear()
            self.query_field.addItem('')
            self.query_field_values = sorted([q for q in self.queries],
                                             key=sort_key)
            self.query_field.addItems(self.query_field_values)
            self.query_field.blockSignals(False)
        self.query_field.setCurrentIndex(self.query_field.findText(name))
Пример #19
0
 def rename():
     title = _("Set Device Label")
     msg = _("Enter new label:")
     response = QInputDialog().getText(dialog, title, msg)
     if not response[1]:
         return
     client().change_label(str(response[0]))
     refresh()
 def insert_link(self, *args):
     link, ok = QInputDialog.getText(self, _('Create link'), _('Enter URL'))
     if not ok:
         return
     url = self.parse_link(unicode(link))
     if url.isValid():
         url = unicode(url.toString())
         self.exec_command('createLink', url)
Пример #21
0
 def create_checkpoint(self):
     text, ok = QInputDialog.getText(
         self.gui, _('Choose name'),
         _('Choose a name for the checkpoint.\nYou can later restore the book'
           ' to this checkpoint via the\n"Revert to..." entries in the Edit menu.'
           ))
     if ok:
         self.add_savepoint(text)
Пример #22
0
 def modify_label():
     response = QInputDialog().getText(None, "Set New KeepKey Label", "New KeepKey Label:  (upon submission confirm on KeepKey)")
     if not response[1]:
         return
     new_label = str(response[0])
     self.handler.show_message("Please confirm label change on KeepKey")
     status = self.get_client().apply_settings(label=new_label)
     self.handler.stop()
     update_label()
Пример #23
0
 def modify_label():
     response = QInputDialog().getText(None, "Set New Trezor Label", "New Trezor Label:  (upon submission confirm on Trezor)")
     if not response[1]:
         return
     new_label = str(response[0])
     twd.start("Please confirm label change on Trezor")
     status = self.wallet.get_client().apply_settings(label=new_label)
     twd.stop()
     update_label()
Пример #24
0
 def create_folder(self, item):
     text, ok = QInputDialog.getText(self, _('Folder name'), _('Enter a name for the new folder'))
     if ok and unicode(text):
         c = QTreeWidgetItem(item, (unicode(text),))
         c.setIcon(0, QIcon(I('mimetypes/dir.png')))
         for item in self.folders.selectedItems():
             item.setSelected(False)
         c.setSelected(True)
         self.folders.setCurrentItem(c)
Пример #25
0
 def insert_link(self, *args):
     link, ok = QInputDialog.getText(self, _('Create link'),
         _('Enter URL'))
     if not ok:
         return
     url = self.parse_link(unicode(link))
     if url.isValid():
         url = unicode(url.toString())
         self.exec_command('createLink', url)
Пример #26
0
 def go_to_line_number(self):
     ed = self.gui.central.current_editor
     if ed is None or not ed.has_line_numbers:
         return
     num, ok = QInputDialog.getInt(self.gui, _('Enter line number'),
                                   ('Line number:'), ed.current_line, 1,
                                   max(100000, ed.number_of_lines))
     if ok:
         ed.current_line = num
Пример #27
0
 def create_folder(self, item):
     text, ok = QInputDialog.getText(self, _('Folder name'),
                                     _('Enter a name for the new folder'))
     if ok and unicode(text):
         c = QTreeWidgetItem(item, (unicode(text), ))
         c.setIcon(0, QIcon(I('mimetypes/dir.png')))
         for item in self.folders.selectedItems():
             item.setSelected(False)
         c.setSelected(True)
         self.folders.setCurrentItem(c)
Пример #28
0
 def expand_rois(fac, percent_increase=None):
     'expand rois by a percentage of the diagonal'
     if percent_increase == None:
         # User ask
         dlg = QInputDialog()
         percentres = dlg.getText(
             None, 'ROI Expansion Factor',
             'Enter the percentage to expand the ROIs.\n' +
             'The percentage is in terms of diagonal length')
         if not percentres[1]:
             logmsg('Cancelled all match')
             return
         try:
             percent_increase = float(str(percentres[0]))
         except ValueError:
             logerr('The percentage must be a number')
     cm = fac.hs.cm
     gm = fac.hs.gm
     logmsg('Resizing all chips')
     for cx in iter(cm.get_valid_cxs()):
         logmsg('Resizing cx=' + str(cx))
         # Get ROI size and Image size
         [rx, ry, rw, rh] = cm.cx2_roi[cx]
         [gw, gh] = gm.gx2_img_size(cm.cx2_gx[cx])
         # Find Diagonal Increase
         diag = np.sqrt(rw**2 + rh**2)
         scale_factor = percent_increase / 100.0
         diag_increase = scale_factor * diag
         target_diag = diag + diag_increase
         # Find Width/Height Increase
         ar = float(rw) / float(rh)
         w_increase = np.sqrt(ar**2 * diag_increase**2 / (ar**2 + 1))
         h_increase = w_increase / ar
         # Find New xywh within image constriants
         new_x = int(max(0, round(rx - w_increase / 2.0)))
         new_y = int(max(0, round(ry - h_increase / 2.0)))
         new_w = int(min(gw - new_x, round(rw + w_increase)))
         new_h = int(min(gh - new_y, round(rh + h_increase)))
         new_roi = [new_x, new_y, new_w, new_h]
         logmsg('Old Roi: ' + repr([rx, ry, rw, rh]))
         cm.change_roi(cx, new_roi)
         logmsg('\n')
     logmsg('Done resizing all chips')
Пример #29
0
 def rename_requested(self, name, location):
     LibraryDatabase = db_class()
     loc = location.replace('/', os.sep)
     base = os.path.dirname(loc)
     newname, ok = QInputDialog.getText(
         self.gui,
         _('Rename') + ' ' + name,
         '<p>' + _('Choose a new name for the library <b>%s</b>. ') % name +
         '<p>' + _('Note that the actual library folder will be renamed.'),
         text=name)
     newname = sanitize_file_name_unicode(unicode(newname))
     if not ok or not newname or newname == name:
         return
     newloc = os.path.join(base, newname)
     if os.path.exists(newloc):
         return error_dialog(
             self.gui,
             _('Already exists'),
             _('The folder %s already exists. Delete it first.') % newloc,
             show=True)
     if (iswindows
             and len(newloc) > LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT):
         return error_dialog(self.gui,
                             _('Too long'),
                             _('Path to library too long. Must be less than'
                               ' %d characters.') %
                             LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT,
                             show=True)
     if not os.path.exists(loc):
         error_dialog(
             self.gui,
             _('Not found'),
             _('Cannot rename as no library was found at %s. '
               'Try switching to this library first, then switch back '
               'and retry the renaming.') % loc,
             show=True)
         return
     try:
         os.rename(loc, newloc)
     except:
         import traceback
         det_msg = 'Location: %r New Location: %r\n%s' % (
             loc, newloc, traceback.format_exc())
         error_dialog(
             self.gui,
             _('Rename failed'),
             _('Failed to rename the library at %s. '
               'The most common cause for this is if one of the files'
               ' in the library is open in another program.') % loc,
             det_msg=det_msg,
             show=True)
         return
     self.stats.rename(location, newloc)
     self.build_menus()
     self.gui.iactions['Copy To Library'].build_menus()
Пример #30
0
 def expand_rois(fac, percent_increase=None):
     'expand rois by a percentage of the diagonal'
     if percent_increase == None:
         # User ask
         dlg = QInputDialog()
         percentres = dlg.getText(None, 'ROI Expansion Factor', 
                                 'Enter the percentage to expand the ROIs.\n'+
                             'The percentage is in terms of diagonal length')
         if not percentres[1]:
             logmsg('Cancelled all match')
             return
         try:
             percent_increase = float(str(percentres[0]))
         except ValueError: 
             logerr('The percentage must be a number')
     cm = fac.hs.cm
     gm = fac.hs.gm
     logmsg('Resizing all chips')
     for cx in iter(cm.get_valid_cxs()):
         logmsg('Resizing cx='+str(cx))
         # Get ROI size and Image size
         [rx, ry, rw, rh] = cm.cx2_roi[cx]
         [gw, gh] = gm.gx2_img_size(cm.cx2_gx[cx])
         # Find Diagonal Increase 
         diag = np.sqrt(rw**2 + rh**2)
         scale_factor = percent_increase/100.0
         diag_increase = scale_factor * diag
         target_diag = diag + diag_increase
         # Find Width/Height Increase 
         ar = float(rw)/float(rh)
         w_increase = np.sqrt(ar**2 * diag_increase**2 / (ar**2 + 1))
         h_increase = w_increase / ar
         # Find New xywh within image constriants 
         new_x = int(max(0, round(rx - w_increase / 2.0)))
         new_y = int(max(0, round(ry - h_increase / 2.0)))
         new_w = int(min(gw - new_x, round(rw + w_increase)))
         new_h = int(min(gh - new_y, round(rh + h_increase)))
         new_roi = [new_x, new_y, new_w, new_h]
         logmsg('Old Roi: '+repr([rx, ry, rw, rh]))
         cm.change_roi(cx, new_roi)
         logmsg('\n')
     logmsg('Done resizing all chips')
Пример #31
0
 def sharpen_image(self):
     val, ok = QInputDialog.getInt(
         self,
         _("Sharpen image"),
         _("The standard deviation for the Gaussian sharpen operation (higher means more sharpening)"),
         value=3,
         min=1,
         max=20,
     )
     if ok:
         self.canvas.sharpen_image(sigma=val)
Пример #32
0
 def blur_image(self):
     val, ok = QInputDialog.getInt(
         self,
         _("Blur image"),
         _("The standard deviation for the Gaussian blur operation (higher means more blurring)"),
         value=3,
         min=1,
         max=20,
     )
     if ok:
         self.canvas.blur_image(sigma=val)
Пример #33
0
    def s_r_save_query(self, *args):
        names = ['']
        names.extend(self.query_field_values)
        try:
            dex = names.index(self.saved_search_name)
        except:
            dex = 0
        name = ''
        while not name:
            name, ok =  QInputDialog.getItem(self, _('Save search/replace'),
                    _('Search/replace name:'), names, dex, True)
            if not ok:
                return
            if not name:
                error_dialog(self, _("Save search/replace"),
                        _("You must provide a name."), show=True)
        new = True
        name = unicode(name)
        if name in self.queries.keys():
            if not question_dialog(self, _("Save search/replace"),
                    _("That saved search/replace already exists and will be overwritten. "
                        "Are you sure?")):
                return
            new = False

        query = {}
        query['name'] = name
        query['search_field'] = unicode(self.search_field.currentText())
        query['search_mode'] = unicode(self.search_mode.currentText())
        query['s_r_template'] = unicode(self.s_r_template.text())
        query['s_r_src_ident'] = unicode(self.s_r_src_ident.currentText())
        query['search_for'] = unicode(self.search_for.text())
        query['case_sensitive'] = self.case_sensitive.isChecked()
        query['replace_with'] = unicode(self.replace_with.text())
        query['replace_func'] = unicode(self.replace_func.currentText())
        query['destination_field'] = unicode(self.destination_field.currentText())
        query['s_r_dst_ident'] = unicode(self.s_r_dst_ident.text())
        query['replace_mode'] = unicode(self.replace_mode.currentText())
        query['comma_separated'] = self.comma_separated.isChecked()
        query['results_count'] = self.results_count.value()
        query['starting_from'] = self.starting_from.value()
        query['multiple_separator'] = unicode(self.multiple_separator.text())

        self.queries[name] = query
        self.queries.commit()

        if new:
            self.query_field.blockSignals(True)
            self.query_field.clear()
            self.query_field.addItem('')
            self.query_field_values = sorted([q for q in self.queries], key=sort_key)
            self.query_field.addItems(self.query_field_values)
            self.query_field.blockSignals(False)
        self.query_field.setCurrentIndex(self.query_field.findText(name))
Пример #34
0
 def create_checkpoint(self):
     text, ok = QInputDialog.getText(
         self.gui,
         _("Choose name"),
         _(
             "Choose a name for the checkpoint.\nYou can later restore the book"
             ' to this checkpoint via the\n"Revert to..." entries in the Edit menu.'
         ),
     )
     if ok:
         self.add_savepoint(text)
Пример #35
0
 def sharpen_image(self):
     val, ok = QInputDialog.getInt(
         self,
         _('Sharpen image'),
         _('The standard deviation for the Gaussian sharpen operation (higher means more sharpening)'
           ),
         value=3,
         min=1,
         max=20)
     if ok:
         self.canvas.sharpen_image(sigma=val)
Пример #36
0
 def blur_image(self):
     val, ok = QInputDialog.getInt(
         self,
         _('Blur image'),
         _('The standard deviation for the Gaussian blur operation (higher means more blurring)'
           ),
         value=3,
         min=1,
         max=20)
     if ok:
         self.canvas.blur_image(sigma=val)
Пример #37
0
 def new_dictionary(self):
     name, ok = QInputDialog.getText(self, _('New dictionary'), _(
         'Name of the new dictionary'))
     if ok:
         name = unicode(name)
         if name in {d.name for d in dictionaries.all_user_dictionaries}:
             return error_dialog(self, _('Already used'), _(
                 'A dictionary with the name %s already exists') % name, show=True)
         dictionaries.create_user_dictionary(name)
         self.dictionaries_changed = True
         self.build_dictionaries(name)
         self.show_current_dictionary()
Пример #38
0
 def save_theme(self):
     themename, ok = QInputDialog.getText(self, _('Theme name'),
                                          _('Choose a name for this theme'))
     if not ok: return
     themename = unicode(themename).strip()
     if not themename: return
     c = config('')
     c.add_opt('theme_name_xxx', default=themename)
     self.save_options(c)
     self.themes['theme_' + themename] = c.src
     self.init_load_themes()
     self.theming_message.setText(
         _('Saved settings as the theme named: %s') % themename)
Пример #39
0
 def save_theme(self):
     themename, ok = QInputDialog.getText(self, _('Theme name'),
             _('Choose a name for this theme'))
     if not ok: return
     themename = unicode(themename).strip()
     if not themename: return
     c = config('')
     c.add_opt('theme_name_xxx', default=themename)
     self.save_options(c)
     self.themes['theme_'+themename] = c.src
     self.init_load_themes()
     self.theming_message.setText(_('Saved settings as the theme named: %s')%
         themename)
Пример #40
0
 def save_settings(self):
     xpaths = self.xpaths
     if not xpaths:
         return error_dialog(self, _('No XPaths'),
                             _('No XPaths have been entered'), show=True)
     if not self.check():
         return
     name, ok = QInputDialog.getText(self, _('Choose name'),
             _('Choose a name for these settings'))
     if ok:
         name = unicode(name).strip()
         if name:
             saved = gprefs.get('xpath_toc_settings', {})
             saved[name] = {i:x for i, x in enumerate(xpaths)}
             gprefs.set('xpath_toc_settings', saved)
             self.setup_load_button()
Пример #41
0
 def save_settings(self):
     if not self.something_selected:
         return error_dialog(self, _('No actions selected'),
             _('You must select at least one action before saving'),
                             show=True)
     name, ok = QInputDialog.getText(self, _('Choose name'),
             _('Choose a name for these settings'))
     if ok:
         name = unicode(name).strip()
         if name:
             settings = {ac:getattr(self, 'opt_'+ac).isChecked() for ac in
                         self.all_actions}
             saved = gprefs.get('polish_settings', {})
             saved[name] = settings
             gprefs.set('polish_settings', saved)
             self.setup_load_button()
Пример #42
0
 def save_settings(self):
     xpaths = self.xpaths
     if not xpaths:
         return error_dialog(self, _('No XPaths'),
                             _('No XPaths have been entered'), show=True)
     if not self.check():
         return
     name, ok = QInputDialog.getText(self, _('Choose name'),
             _('Choose a name for these settings'))
     if ok:
         name = unicode(name).strip()
         if name:
             saved = gprefs.get('xpath_toc_settings', {})
             saved[name] = {i:x for i, x in enumerate(xpaths)}
             gprefs.set('xpath_toc_settings', saved)
             self.setup_load_button()
Пример #43
0
 def save_settings(self):
     if not self.something_selected:
         return error_dialog(self, _('No actions selected'),
             _('You must select at least one action before saving'),
                             show=True)
     name, ok = QInputDialog.getText(self, _('Choose name'),
             _('Choose a name for these settings'))
     if ok:
         name = unicode(name).strip()
         if name:
             settings = {ac:getattr(self, 'opt_'+ac).isChecked() for ac in
                         self.all_actions}
             saved = gprefs.get('polish_settings', {})
             saved[name] = settings
             gprefs.set('polish_settings', saved)
             self.setup_load_button()
Пример #44
0
 def add_mapping(self):
     new_genre_name, ok = QInputDialog.getText(self, 'Add new mapping',
                 'Enter a Shelfari genre name to create a mapping for:', text='')
     if not ok:
         # Operation cancelled
         return
     new_genre_name = unicode(new_genre_name).strip()
     if not new_genre_name:
         return
     # Verify it does not clash with any other mappings in the list
     data = self.edit_table.get_data()
     for genre_name in data.keys():
         if genre_name.lower() == new_genre_name.lower():
             return error_dialog(self, 'Add Failed', 'A genre with the same name already exists', show=True)
     data[new_genre_name] = []
     self.edit_table.populate_table(data)
     self.edit_table.select_genre(new_genre_name)
Пример #45
0
 def bookmark(self, *args):
     num = 1
     bm = None
     while True:
         bm = _('Bookmark #%d')%num
         if bm not in self.existing_bookmarks:
             break
         num += 1
     title, ok = QInputDialog.getText(self, _('Add bookmark'),
             _('Enter title for bookmark:'), text=bm)
     title = unicode(title).strip()
     if ok and title:
         bm = self.view.bookmark()
         bm['spine'] = self.current_index
         bm['title'] = title
         self.iterator.add_bookmark(bm)
         self.set_bookmarks(self.iterator.bookmarks)
Пример #46
0
def debug_runpycode_from_a_dialog(source="some debug menu??"):
    # TODO: rewrite this to call grab_text_using_dialog (should be easy)
    title = "debug: run py code"
    label = "one line of python to exec in debug.py's globals()\n(or use @@@ to fake \\n for more lines)\n(or use execfile)"
    parent = None
    #bruce 070329 Qt4 bugfix -- in Qt4 a new first argument (parent) is needed by QInputDialog.getText.
    # [FYI, for a useful reference to QInputDialog with lots of extra info, see
    #  http://www.bessrc.aps.anl.gov/software/qt4-x11-4.2.2-browser/d9/dcb/class_q_input_dialog.html ]
    text, ok = QInputDialog.getText(parent, title, label)
    if ok:
        # fyi: type(text) == <class '__main__.qt.QString'>
        command = str(text)
        command = command.replace("@@@", '\n')
        debug_run_command(command, source=source)
    else:
        print "run py code: cancelled"
    return
Пример #47
0
def debug_runpycode_from_a_dialog( source = "some debug menu??"):
    # TODO: rewrite this to call grab_text_using_dialog (should be easy)
    title = "debug: run py code"
    label = "one line of python to exec in debug.py's globals()\n(or use @@@ to fake \\n for more lines)\n(or use execfile)"
    parent = None
        #bruce 070329 Qt4 bugfix -- in Qt4 a new first argument (parent) is needed by QInputDialog.getText.
        # [FYI, for a useful reference to QInputDialog with lots of extra info, see
        #  http://www.bessrc.aps.anl.gov/software/qt4-x11-4.2.2-browser/d9/dcb/class_q_input_dialog.html ]
    text, ok = QInputDialog.getText(parent, title, label)
    if ok:
        # fyi: type(text) == <class '__main__.qt.QString'>
        command = str(text)
        command = command.replace("@@@",'\n')
        debug_run_command(command, source = source)
    else:
        print "run py code: cancelled"
    return
Пример #48
0
 def rename_dictionary(self):
     d = self.current_dictionary
     if d is None:
         return
     name, ok = QInputDialog.getText(self, _('New name'), _(
         'New name for the dictionary'))
     if ok:
         name = unicode(name)
         if name == d.name:
             return
         if name in {d.name for d in dictionaries.all_user_dictionaries}:
             return error_dialog(self, _('Already used'), _(
                 'A dictionary with the name %s already exists') % name, show=True)
         if dictionaries.rename_user_dictionary(d.name, name):
             self.build_dictionaries(name)
             self.dictionaries_changed = True
             self.show_current_dictionary()
Пример #49
0
def grab_text_line_using_dialog(
        default="",
        title="title",
        label="label",
        iconPath="ui/border/MainWindow"):  #bruce 070531
    """
    Use a dialog to get one line of text from the user, with given default 
    (initial) value, dialog window title, and label text inside the dialog.
    If successful, return (True, text);
    if not, return (False, "Reason why not").
    Returned text is a python string (not unicode).
    """
    # WARNING: several routines contain very similar code.
    # We should combine them into one (see comment before this function).
    # This function was modified from grab_text_line_using_dialog() (above)
    # which was modified from _set_test_from_dialog(),
    # which was modified from debug_runpycode_from_a_dialog(),
    # which does the "run py code" debug menu command.

    inputDialog = QDialog()  # No parent
    inputDialog.setWindowIcon(geticon(iconPath))

    text, ok = QInputDialog.getText(inputDialog, title, label,
                                    QLineEdit.Normal, default)
    # note: parent arg needed only in Qt4
    if not ok:
        reason = "Cancelled"
    if ok:
        try:
            # fyi: type(text) == <class '__main__.qt.QString'>
            text = str(text)  ###BUG: won't work for unicode
        except:
            ok = False
            reason = "Unicode is not yet supported"
        ## text = text.replace("@@@",'\n')
    if ok:
        return True, text
    else:
        return False, reason
    pass
Пример #50
0
def grab_text_using_dialog( default = "", 
                            title = "title", 
                            label = "label",
                            iconPath  = "ui/border/MainWindow.png"):
    """
    Get some text from the user by putting up a dialog with the
    supplied title, label, and default text. Return (ok, text)
    as described below.

    Replace @@@ with \n in the returned text (and convert it to a Python
    string). If it contains unicode characters, raise UnicodeEncodeError.

    @return: the 2-tuple (ok, text), which is (True, text) if we succeed,
             or (False, None) if the user cancels.
    """
    # TODO: add an option to allow this to accept unicode,
    # and do something better if that's not provided and unicode is entered
    # (right now it just raises a UnicodeEncodeError).
    
    # modified from _set_test_from_dialog( ),
    # which was modified from debug_runpycode_from_a_dialog,
    # which does the "run py code" debug menu command
    
    # Qt4 version [070329; similar code in an exprs-module file]
    
    inputDialog = QDialog() # No parent
    inputDialog.setWindowIcon(geticon(iconPath))
    
    text, ok = QInputDialog.getText(inputDialog, title, label,
                                    QLineEdit.Normal, default)
        # note: parent arg is needed in Qt4, not in Qt3
    
    if ok:
        # fyi: type(text) == <class '__main__.qt.QString'>
        text = str(text)
        text = text.replace("@@@",'\n')
    else:
        pass # print "grab_text_using_dialog: cancelled"
    return ok, text
 def rename_genre(self):
     selected_genre = self.edit_table.get_selected_genre()
     if not selected_genre:
         return
     new_genre_name, ok = QInputDialog.getText(self, 'Add new mapping',
                 'Enter a Aladin genre name to create a mapping for:', text=selected_genre)
     if not ok:
         # Operation cancelled
         return
     new_genre_name = unicode(new_genre_name).strip()
     if not new_genre_name or new_genre_name == selected_genre:
         return
     data = self.edit_table.get_data()
     if new_genre_name.lower() != selected_genre.lower():
         # Verify it does not clash with any other mappings in the list
         for genre_name in data.keys():
             if genre_name.lower() == new_genre_name.lower():
                 return error_dialog(self, 'Rename Failed', 'A genre with the same name already exists', show=True)
     data[new_genre_name] = data[selected_genre]
     del data[selected_genre]
     self.edit_table.populate_table(data)
     self.edit_table.select_genre(new_genre_name)
Пример #52
0
def grab_text_line_using_dialog(
    default="", title="title", label="label", iconPath="ui/border/MainWindow.png"
):  # bruce 070531
    """
    Use a dialog to get one line of text from the user, with given default 
    (initial) value, dialog window title, and label text inside the dialog.
    If successful, return (True, text);
    if not, return (False, "Reason why not").
    Returned text is a python string (not unicode).
    """
    # WARNING: several routines contain very similar code.
    # We should combine them into one (see comment before this function).
    # This function was modified from grab_text_line_using_dialog() (above)
    # which was modified from _set_test_from_dialog(),
    # which was modified from debug_runpycode_from_a_dialog(),
    # which does the "run py code" debug menu command.

    inputDialog = QDialog()  # No parent
    inputDialog.setWindowIcon(geticon(iconPath))

    text, ok = QInputDialog.getText(inputDialog, title, label, QLineEdit.Normal, default)
    # note: parent arg needed only in Qt4
    if not ok:
        reason = "Cancelled"
    if ok:
        try:
            # fyi: type(text) == <class '__main__.qt.QString'>
            text = str(text)  ###BUG: won't work for unicode
        except:
            ok = False
            reason = "Unicode is not yet supported"
        ## text = text.replace("@@@",'\n')
    if ok:
        return True, text
    else:
        return False, reason
    pass
Пример #53
0
 def __init__(self, pa, parent):
     QDialog.__init__(self, parent)
     TE_Dialog.__init__(self)
     self.setupUi(self)
     opts = smtp_prefs().parse()
     self.test_func = parent.test_email_settings
     self.test_button.clicked.connect(self.test)
     self.from_.setText(unicode(self.from_.text()) % opts.from_)
     if pa:
         self.to.setText(pa)
     if opts.relay_host:
         tmp_password = ''
         if opts.relay_prompt:
             header = opts.relay_username + '@' + opts.relay_host
             tmp_password, ok = QInputDialog.getText(
                 self,
                 header,
                 _('Password:'******''
             else:
                 conf = smtp_prefs()
                 conf.set('relay_password',
                          hexlify(str(tmp_password).encode('utf-8')))
                 tmp_password = '******'
         else:
             tmp_password = unhexlify(opts.relay_password).decode('utf-8')
         self.label.setText(
             _('Using: %(un)s:%(pw)s@%(host)s:%(port)s and %(enc)s encryption'
               ) % dict(un=opts.relay_username,
                        pw=tmp_password,
                        host=opts.relay_host,
                        port=opts.relay_port,
                        enc=opts.encryption))
Пример #54
0
    def computeImage(self, expression=None):
        """Computes image from expression (if expression is None, pops up dialog)"""
        if expression is None:
            (expression, ok) = QInputDialog.getText(
                self, "Compute image", """Enter an image expression to compute.
                                              Any valid numpy expression is supported, and
                                              all functions from the numpy module are available (including sub-modules such as fft).
                                              Use 'a', 'b', 'c' to refer to images.
                                              Examples:  "(a+b)/2", "cos(a)+sin(b)", "a-a.mean()", "fft.fft2(a)", etc."""
            )
            #      (expression,ok) = QInputDialog.getText(self,"Compute image","""<P>Enter an expression to compute.
            #        Use 'a', 'b', etc. to refer to loaded images. Any valid numpy expression is supported, and all the
            #       functions from the numpy module are available. Examples of valid expressions include "(a+b)/2",
            #       "cos(a)+sin(b)", "a-a.mean()", etc.
            #        </P>
            #      """)
            expression = str(expression)
            if not ok or not expression:
                return
        # try to parse expression
        arglist = [(chr(ord('a') + ic.getNumber()), ic.image)
                   for ic in self._imagecons]
        try:
            exprfunc = eval(
                "lambda " + (",".join([x[0]
                                       for x in arglist])) + ":" + expression,
                numpy.__dict__, {})
        except Exception as exc:
            self.showErrorMessage("""Error parsing expression "%s": %s.""" %
                                  (expression, str(exc)))
            return None
        # try to evaluate expression
        self.showMessage("Computing expression \"%s\"" % expression, 10000)
        busy = BusyIndicator()
        QApplication.flush()

        # trim trivial trailing dimensions. This avoids the problem of when an NxMx1 and an NxMx1x1 arrays are added,
        # the result is promoted to NxMxMx1 following the numpy rules.
        def trimshape(shape):
            out = shape
            while out and out[-1] == 1:
                out = out[:-1]
            return out

        def trimarray(array):
            return array.reshape(trimshape(array.shape))

        try:
            result = exprfunc(*[trimarray(x[1].data()) for x in arglist])
        except Exception as exc:
            busy = None
            traceback.print_exc()
            self.showErrorMessage("""Error evaluating "%s": %s.""" %
                                  (expression, str(exc)))
            return None
        busy = None
        if type(result) != numpy.ma.masked_array and type(
                result) != numpy.ndarray:
            self.showErrorMessage(
                """Result of "%s" is of invalid type "%s" (array expected)."""
                % (expression, type(result).__name__))
            return None
        # convert coomplex results to real
        if numpy.iscomplexobj(result):
            self.showErrorMessage(
                """Result of "%s" is complex. Complex images are currently
      not fully supported, so we'll implicitly use the absolute value instead."""
                % (expression))
            expression = "abs(%s)" % expression
            result = abs(result)
        # determine which image this expression can be associated with
        res_shape = trimshape(result.shape)
        arglist = [
            x for x in arglist if hasattr(x[1], 'fits_header')
            and trimshape(x[1].data().shape) == res_shape
        ]
        if not arglist:
            self.showErrorMessage(
                """Result of "%s" has shape %s, which does not match any loaded FITS image."""
                % (expression, "x".join(map(str, result.shape))))
            return None
        # look for an image in the arglist with the same projection, and with a valid dirname
        # (for the where-to-save hint)
        template = arglist[0][1]
        # if all images in arglist have the same projection, then it doesn't matter what we use
        # else ask
        if len(
            [x for x in arglist[1:] if x[1].projection == template.projection
             ]) != len(arglist) - 1:
            options = [x[0] for x in arglist]
            (which, ok) = QInputDialog.getItem(
                self, "Compute image",
                "Coordinate system to use for the result of \"%s\":" %
                expression, options, 0, False)
            if not ok:
                return None
            try:
                template = arglist[options.index(which)][1]
            except:
                pass
        # create a FITS image
        busy = BusyIndicator()
        dprint(2, "creating FITS image", expression)
        self.showMessage("""Creating image for %s""" % expression, 3000)
        QApplication.flush()
        try:
            hdu = pyfits.PrimaryHDU(result.transpose(), template.fits_header)
            skyimage = SkyImage.FITSImagePlotItem(name=expression,
                                                  filename=None,
                                                  hdu=hdu)
        except:
            busy = None
            traceback.print_exc()
            self.showErrorMessage("""Error creating FITS image %s: %s""" %
                                  (expression, str(sys.exc_info()[1])))
            return None
        # get directory name for save-to hint
        dirname = getattr(template, 'filename', None)
        if not dirname:
            dirnames = [
                getattr(img, 'filename') for x, img in arglist
                if hasattr(img, 'filename')
            ]
            dirname = dirnames[0] if dirnames else None
        # create control bar, add to widget stack
        self._createImageController(
            skyimage,
            expression,
            expression,
            save=((dirname and os.path.dirname(dirname)) or "."))
        self.showMessage("Created new image for %s" % expression, 3000)
        dprint(2, "image created")
Пример #55
0
    def computeImage(self, expression=None):
        """Computes image from expression (if expression is None, pops up dialog)"""
        if expression is None:
            (expression, ok) = QInputDialog.getText(self, "Compute image",
                                                    """Enter an image expression to compute.
                                              Any valid numpy expression is supported, and
                                              all functions from the numpy module are available (including sub-modules such as fft).
                                              Use 'a', 'b', 'c' to refer to images.
                                              Examples:  "(a+b)/2", "cos(a)+sin(b)", "a-a.mean()", "fft.fft2(a)", etc.""")
            #      (expression,ok) = QInputDialog.getText(self,"Compute image","""<P>Enter an expression to compute.
            #        Use 'a', 'b', etc. to refer to loaded images. Any valid numpy expression is supported, and all the
            #       functions from the numpy module are available. Examples of valid expressions include "(a+b)/2",
            #       "cos(a)+sin(b)", "a-a.mean()", etc.
            #        </P>
            #      """)
            expression = str(expression)
            if not ok or not expression:
                return
        # try to parse expression
        arglist = [(chr(ord('a') + ic.getNumber()), ic.image) for ic in self._imagecons]
        try:
            exprfunc = eval("lambda " + (",".join([x[0] for x in arglist])) + ":" + expression,
                            numpy.__dict__, {})
        except Exception as exc:
            self.showErrorMessage("""Error parsing expression "%s": %s.""" % (expression, str(exc)))
            return None
        # try to evaluate expression
        self.showMessage("Computing expression \"%s\"" % expression, 10000)
        busy = BusyIndicator()
        QApplication.flush()

        # trim trivial trailing dimensions. This avoids the problem of when an NxMx1 and an NxMx1x1 arrays are added,
        # the result is promoted to NxMxMx1 following the numpy rules.
        def trimshape(shape):
            out = shape
            while out and out[-1] == 1:
                out = out[:-1]
            return out

        def trimarray(array):
            return array.reshape(trimshape(array.shape))

        try:
            result = exprfunc(*[trimarray(x[1].data()) for x in arglist])
        except Exception as exc:
            busy = None
            traceback.print_exc()
            self.showErrorMessage("""Error evaluating "%s": %s.""" % (expression, str(exc)))
            return None
        busy = None
        if type(result) != numpy.ma.masked_array and type(result) != numpy.ndarray:
            self.showErrorMessage(
                """Result of "%s" is of invalid type "%s" (array expected).""" % (expression, type(result).__name__))
            return None
        # convert coomplex results to real
        if numpy.iscomplexobj(result):
            self.showErrorMessage("""Result of "%s" is complex. Complex images are currently
      not fully supported, so we'll implicitly use the absolute value instead.""" % (expression))
            expression = "abs(%s)" % expression
            result = abs(result)
        # determine which image this expression can be associated with
        res_shape = trimshape(result.shape)
        arglist = [x for x in arglist if hasattr(x[1], 'fits_header') and trimshape(x[1].data().shape) == res_shape]
        if not arglist:
            self.showErrorMessage("""Result of "%s" has shape %s, which does not match any loaded FITS image.""" % (
            expression, "x".join(map(str, result.shape))))
            return None
        # look for an image in the arglist with the same projection, and with a valid dirname
        # (for the where-to-save hint)
        template = arglist[0][1]
        # if all images in arglist have the same projection, then it doesn't matter what we use
        # else ask
        if len([x for x in arglist[1:] if x[1].projection == template.projection]) != len(arglist) - 1:
            options = [x[0] for x in arglist]
            (which, ok) = QInputDialog.getItem(self, "Compute image",
                                               "Coordinate system to use for the result of \"%s\":" % expression,
                                               options, 0, False)
            if not ok:
                return None
            try:
                template = arglist[options.index(which)][1]
            except:
                pass
        # create a FITS image
        busy = BusyIndicator()
        dprint(2, "creating FITS image", expression)
        self.showMessage("""Creating image for %s""" % expression, 3000)
        QApplication.flush()
        try:
            hdu = pyfits.PrimaryHDU(result.transpose(), template.fits_header)
            skyimage = SkyImage.FITSImagePlotItem(name=expression, filename=None, hdu=hdu)
        except:
            busy = None
            traceback.print_exc()
            self.showErrorMessage("""Error creating FITS image %s: %s""" % (expression, str(sys.exc_info()[1])))
            return None
        # get directory name for save-to hint
        dirname = getattr(template, 'filename', None)
        if not dirname:
            dirnames = [getattr(img, 'filename') for x, img in arglist if hasattr(img, 'filename')]
            dirname = dirnames[0] if dirnames else None
        # create control bar, add to widget stack
        self._createImageController(skyimage, expression, expression,
                                    save=((dirname and os.path.dirname(dirname)) or "."))
        self.showMessage("Created new image for %s" % expression, 3000)
        dprint(2, "image created")