Source code for ibeis.gui.newgui

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
"""
This should probably be renamed guifront.py This defines all of the visual
components to the GUI It is invoked from guiback, which handles the nonvisual
logic.


BUGS:
    * Copying the ungrouped imageset raises an error. Should have the option
    to copy or move it. Other special imageset should not have this option.

    Should gray out an option if it is not available.


"""
from __future__ import absolute_import, division, print_function
from six.moves import zip, map, filter  # NOQA
from os.path import isdir
import sys
from ibeis import constants as const
import functools
from guitool.__PYQT__ import QtGui, QtCore
from guitool.__PYQT__.QtCore import Qt
from guitool.__PYQT__.QtGui import QSizePolicy
from guitool import signal_, slot_, checks_qt_error, ChangeLayoutContext, BlockContext  # NOQA
from ibeis.other import ibsfuncs
from ibeis.gui import guiheaders as gh
from ibeis.gui import guimenus
import six
from ibeis.viz.interact import interact_annotations2
from ibeis.gui.guiheaders import (IMAGE_TABLE, IMAGE_GRID, ANNOTATION_TABLE, NAME_TABLE, NAMES_TREE, IMAGESET_TABLE)  # NOQA
from ibeis.gui.models_and_views import (IBEISStripeModel, IBEISTableView,
                                        IBEISItemModel, IBEISTreeView,
                                        ImagesetTableModel, ImagesetTableView,
                                        IBEISTableWidget, IBEISTreeWidget,
                                        ImagesetTableWidget)
import guitool
from plottool import color_funcs
import utool as ut
import plottool as pt
print, print_, printDBG, rrr, profile = ut.inject(__name__, '[newgui]')


VERBOSE_GUI = ut.VERBOSE or ut.get_argflag(('--verbose-gui', '--verbgui'))
WITH_GUILOG = ut.get_argflag('--guilog')
#WITH_GUILOG = not ut.get_argflag('--noguilog')

"""
from ibeis.gui.guiheaders import (IMAGE_TABLE, IMAGE_GRID, ANNOTATION_TABLE,
                                  NAME_TABLE, NAMES_TREE, IMAGESET_TABLE)
ibsgwt = back.front
view   = ibsgwt.views[IMAGE_TABLE]
model  = ibsgwt.models[IMAGE_TABLE]
row = model.get_row_from_id(3)
view.selectRow(row)
"""

#############################
###### Tab Widgets #######
#############################


[docs]class APITabWidget(QtGui.QTabWidget): """ Holds the table-tabs use setCurrentIndex to change the selection """ def __init__(tabwgt, parent=None, horizontalStretch=1): QtGui.QTabWidget.__init__(tabwgt, parent) tabwgt.ibswgt = parent tabwgt._sizePolicy = guitool.newSizePolicy( tabwgt, horizontalStretch=horizontalStretch) tabwgt.setSizePolicy(tabwgt._sizePolicy) #tabwgt.currentChanged.connect(tabwgt.setCurrentIndex) tabwgt.currentChanged.connect(tabwgt._on_tabletab_change) tabwgt.current_tblname = None @slot_(int) def _on_tabletab_change(tabwgt, index): """ Switch to the current imageset tab """ print('[apitab] _onchange(index=%r)' % (index,)) tblname = tabwgt.ibswgt.tblname_list[index] tabwgt.current_tblname = tblname print('[apitab] _onchange(tblname=%r)' % (tblname,)) tabwgt.ibswgt.back._clear_selection() view = tabwgt.ibswgt.views[tblname] selected = view.selectionModel().selection() deselected = QtGui.QItemSelection() tabwgt.ibswgt.update_selection(selected, deselected) #tabwgt.ibswgt.back.update_selection_texts() #def setCurrentIndex(tabwgt, index): # tblname = tabwgt.ibswgt.tblname_list[index] # print('Set %r current Index: %r ' % (tblname, index)) # #model = tabwgt.ibswgt.models[tblname] # #with ChangeLayoutContext([model]): # # QtGui.QTabWidget.setCurrentIndex(tabwgt, index)
[docs]class ImagesetTabWidget(QtGui.QTabWidget): """ Handles the super-tabs for the imagesets that hold the table-tabs """ def __init__(imageset_tabwgt, parent=None, horizontalStretch=1): QtGui.QTabWidget.__init__(imageset_tabwgt, parent) imageset_tabwgt.ibswgt = parent imageset_tabwgt.setTabsClosable(True) imageset_tabwgt.setMaximumSize(9999, guitool.get_cplat_tab_height()) imageset_tabwgt.tabbar = imageset_tabwgt.tabBar() imageset_tabwgt.tabbar.setMovable(False) imageset_tabwgt.setStyleSheet('border: none;') imageset_tabwgt.tabbar.setStyleSheet('border: none;') sizePolicy = guitool.newSizePolicy(imageset_tabwgt, horizontalStretch=horizontalStretch) imageset_tabwgt.setSizePolicy(sizePolicy) imageset_tabwgt.tabCloseRequested.connect(imageset_tabwgt._close_tab) imageset_tabwgt.currentChanged.connect(imageset_tabwgt._on_imagesettab_change) imageset_tabwgt.imgsetid_list = [] # TURNING ON / OFF ALL IMAGES # imageset_tabwgt._add_imageset_tab(-1, const.ALL_IMAGE_IMAGESETTEXT) @slot_(int) def _on_imagesettab_change(imageset_tabwgt, index): """ Switch to the current imageset tab """ print('[imageset_tab_widget] _onchange(index=%r)' % (index,)) if 0 <= index and index < len(imageset_tabwgt.imgsetid_list): imgsetid = imageset_tabwgt.imgsetid_list[index] #if ut.VERBOSE: print('[IMAGESETTAB.ONCHANGE] imgsetid = %r' % (imgsetid,)) imageset_tabwgt.ibswgt._change_imageset(imgsetid) else: imageset_tabwgt.ibswgt._change_imageset(-1) @slot_(int) def _close_tab(imageset_tabwgt, index): print('[imageset_tab_widget] _close_tab(index=%r)' % (index,)) if imageset_tabwgt.imgsetid_list[index] is not None: imageset_tabwgt.imgsetid_list.pop(index) imageset_tabwgt.removeTab(index) @slot_() def _close_all_tabs(imageset_tabwgt): print('[imageset_tab_widget] _close_all_tabs()') while len(imageset_tabwgt.imgsetid_list) > 0: index = 0 imageset_tabwgt.imgsetid_list.pop(index) imageset_tabwgt.removeTab(index) @slot_(int) def _close_tab_with_imgsetid(imageset_tabwgt, imgsetid): print('[imageset_tab_widget] _close_tab_with_imgsetid(imgsetid=%r)' % (imgsetid)) try: index = imageset_tabwgt.imgsetid_list.index(imgsetid) imageset_tabwgt._close_tab(index) except: pass def _add_imageset_tab(imageset_tabwgt, imgsetid, imagesettext): print('[_add_imageset_tab] imgsetid=%r, imagesettext=%r' % (imgsetid, imagesettext)) if imgsetid not in imageset_tabwgt.imgsetid_list: tab_name = str(imagesettext) imageset_tabwgt.addTab(QtGui.QWidget(), tab_name) imageset_tabwgt.imgsetid_list.append(imgsetid) index = len(imageset_tabwgt.imgsetid_list) - 1 else: index = imageset_tabwgt.imgsetid_list.index(imgsetid) imageset_tabwgt.setCurrentIndex(index) imageset_tabwgt._on_imagesettab_change(index) def _update_imageset_tab_name(imageset_tabwgt, imgsetid, imagesettext): for index, _id in enumerate(imageset_tabwgt.imgsetid_list): if imgsetid == _id: imageset_tabwgt.setTabText(index, imagesettext) ############################# ######## Main Widget ######## #############################
[docs]class IBEISMainWindow(QtGui.QMainWindow): quitSignal = signal_() dropSignal = signal_(list) def __init__(mainwin, back=None, ibs=None, parent=None): QtGui.QMainWindow.__init__(mainwin, parent) # Menus mainwin.setUnifiedTitleAndToolBarOnMac(False) guimenus.setup_menus(mainwin, back) # Central Widget mainwin.ibswgt = IBEISGuiWidget(back=back, ibs=ibs, parent=mainwin) mainwin.setCentralWidget(mainwin.ibswgt) mainwin.setAcceptDrops(True) if back is not None: mainwin.quitSignal.connect(back.quit) else: raise AssertionError('need backend') mainwin.dropSignal.connect(mainwin.ibswgt.imagesDropped) # mainwin.resize(900, 600) @slot_()
[docs] def closeEvent(mainwin, event): event.accept() mainwin.quitSignal.emit()
[docs] def dragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ignore()
[docs] def dropEvent(self, event): if event.mimeData().hasUrls: event.setDropAction(QtCore.Qt.CopyAction) event.accept() links = [] for url in event.mimeData().urls(): links.append(str(url.toLocalFile())) self.dropSignal.emit(links) else: event.ignore()
@slot_()
[docs] def expand_names_tree(mainwin): view = mainwin.ibswgt.views[gh.NAMES_TREE] view.expandAll() ############################# ##### IBEIS GUI Widget ###### #############################
IBEIS_WIDGET_BASE = QtGui.QWidget
[docs]class IBEISGuiWidget(IBEIS_WIDGET_BASE): """ CommandLine: # Testing python -m ibeis --db NNP_Master3 --onlyimgtbl python -m ibeis --db PZ_Master1 --onlyimgtbl """ def __init__(ibswgt, back=None, ibs=None, parent=None): IBEIS_WIDGET_BASE.__init__(ibswgt, parent) ibswgt.ibs = ibs ibswgt.back = back # Structures that will hold models and views ibswgt.models = {} ibswgt.views = {} ibswgt.redirects = {} # FIXME: Duplicate models # Create models and views # Define the abstract item models and views for the tables ibswgt.tblname_list = [] ibswgt.modelview_defs = [] # NEW DYNAMIC WAY OF USING TABS AND API VIEWS # ADD IMAGE TABLE if True: ibswgt.tblname_list.append(IMAGE_TABLE) ibswgt.modelview_defs.append((IMAGE_TABLE, IBEISTableWidget, IBEISItemModel, IBEISTableView)) # ADD IMAGE GRID if not ut.get_argflag('--onlyimgtbl'): ibswgt.tblname_list.append(IMAGE_GRID) ibswgt.modelview_defs.append((IMAGE_GRID, IBEISTableWidget, IBEISStripeModel, IBEISTableView)) # ADD ANNOT GRID if not (ut.get_argflag('--noannottbl') or ut.get_argflag('--onlyimgtbl')): ibswgt.tblname_list.append(gh.ANNOTATION_TABLE) ibswgt.modelview_defs.append((gh.ANNOTATION_TABLE, IBEISTableWidget, IBEISItemModel, IBEISTableView)) # ADD NAME TREE if not (ut.get_argflag('--nonametree') or ut.get_argflag('--onlyimgtbl')): ibswgt.tblname_list.append(NAMES_TREE) ibswgt.modelview_defs.append((NAMES_TREE, IBEISTreeWidget, IBEISItemModel, IBEISTreeView)) # ADD IMAGESET TABLE ibswgt.super_tblname_list = ibswgt.tblname_list + [IMAGESET_TABLE] ibswgt.modelview_defs.append((IMAGESET_TABLE, ImagesetTableWidget, ImagesetTableModel, ImagesetTableView)) # DO INITALIZATION # Create and layout components ibswgt._init_components() ibswgt._init_layout() # Connect signals and slots ibswgt._connect_signals_and_slots() # Connect the IBEIS control ibswgt.connect_ibeis_control(ibswgt.ibs) def _connect_signals_and_slots(ibswgt): print('[newgui] _connect_signals_and_slots') for tblname in ibswgt.super_tblname_list: tblview = ibswgt.views[tblname] tblview.doubleClicked.connect(ibswgt.on_doubleclick) tblview.contextMenuClicked.connect(ibswgt.on_contextMenuClicked) if tblname != gh.IMAGESET_TABLE: tblview.selectionModel().selectionChanged.connect(ibswgt.update_selection) #front.printSignal.connect(back.backend_print) #front.raiseExceptionSignal.connect(back.backend_exception) # CONNECT HOOK TO GET NUM ROWS tblview.rows_updated.connect(ibswgt.on_rows_updated) @slot_(QtGui.QItemSelection, QtGui.QItemSelection)
[docs] def update_selection(ibswgt, selected, deselected): """ Quirky behavior: if you select two columns in a row and then unselect only one, the whole row is unselected, because this function only deals with deltas. Example: >>> # DISABLE_DOCTEST >>> from ibeis.gui.newgui import * # NOQA >>> ibs, back, ibswgt, testdata_main_loop = testdata_guifront() >>> ibswgt.set_table_tab(gh.NAMES_TREE) >>> view = ibswgt.views[gh.NAMES_TREE] >>> view.expandAll() >>> AUTOSELECT = False >>> if AUTOSELECT: ... view.selectAll() >>> selmodel = view.selectionModel() >>> selected = selmodel.selection() >>> deselected = QtGui.QItemSelection() >>> # verify results >>> print(result) """ #print('selected = ' + str(selected.indexes())) #print('deselected = ' + str(deselected.indexes())) deselected_model_index_list_ = deselected.indexes() selected_model_index_list_ = selected.indexes() def get_selection_info(model_index_list_): model_index_list = [qtindex for qtindex in model_index_list_ if qtindex.isValid()] model_list = [qtindex.model() for qtindex in model_index_list] tablename_list = [model.name for model in model_list] level_list = [model._get_level(qtindex) for model, qtindex in zip(model_list, model_index_list)] rowid_list = [model._get_row_id(qtindex) for model, qtindex in zip(model_list, model_index_list)] table_key_list = list(zip(tablename_list, level_list)) return table_key_list, rowid_list select_table_key_list, select_rowid_list = get_selection_info( selected_model_index_list_) deselect_table_key_list, deselect_rowid_list = get_selection_info( deselected_model_index_list_) table_key2_selected_rowids = dict(ut.group_items(select_rowid_list, select_table_key_list)) table_key2_deselected_rowids = dict(ut.group_items(deselect_rowid_list, deselect_table_key_list)) table_key2_selected_rowids = {key: list(set(val)) for key, val in six.iteritems(table_key2_selected_rowids)} table_key2_deselected_rowids = {key: list(set(val)) for key, val in six.iteritems(table_key2_deselected_rowids)} if ut.VERBOSE: print('table_key2_selected_rowids = ' + ut.dict_str(table_key2_selected_rowids)) print('table_key2_deselected_rowids = ' + ut.dict_str(table_key2_deselected_rowids)) gh_const_tablename_map = { (IMAGE_TABLE, 0) : const.IMAGE_TABLE, (IMAGE_GRID, 0) : const.IMAGE_TABLE, (gh.ANNOTATION_TABLE, 0) : const.ANNOTATION_TABLE, (NAME_TABLE, 0) : const.NAME_TABLE, (NAMES_TREE, 0) : const.NAME_TABLE, (NAMES_TREE, 1) : const.ANNOTATION_TABLE, } # here tablename is a backend const tablename for table_key, id_list in six.iteritems(table_key2_deselected_rowids): tablename = gh_const_tablename_map[table_key] ibswgt.back._set_selection3(tablename, id_list, mode='diff') for table_key, id_list in six.iteritems(table_key2_selected_rowids): tablename = gh_const_tablename_map[table_key] ibswgt.back._set_selection3(tablename, id_list, mode='add') ibswgt.back.update_selection_texts() #tblview.selectionModel().selectedIndexes()
def _init_components(ibswgt): """ Defines gui components """ # Layout ibswgt.vlayout = QtGui.QVBoxLayout(ibswgt) #ibswgt.hsplitter = guitool.newSplitter(ibswgt, Qt.Horizontal, verticalStretch=18) ibswgt.hsplitter = guitool.newSplitter(ibswgt, Qt.Horizontal, verticalStretch=18) ibswgt.vsplitter = guitool.newSplitter(ibswgt, Qt.Vertical) #ibswgt.hsplitter = guitool.newWidget(ibswgt, Qt.Horizontal, verticalStretch=18) #ibswgt.vsplitter = guitool.newWidget(ibswgt) # # Tables Tab ibswgt._table_tab_wgt = APITabWidget(ibswgt, horizontalStretch=81) #guitool.newTabWidget(ibswgt, horizontalStretch=81) for tblname, WidgetClass, ModelClass, ViewClass in ibswgt.modelview_defs: #widget = WidgetClass(parent=ibswgt) #ibswgt.widgets[tblname] = widget #ibswgt.models[tblname] = widget.model #ibswgt.views[tblname] = widget.view ibswgt.views[tblname] = ViewClass(parent=ibswgt) # Make view first to pass as parent # FIXME: It is very bad to give the model a view. Only the view should have a model ibswgt.models[tblname] = ModelClass(parent=ibswgt.views[tblname]) # Connect models and views for tblname in ibswgt.super_tblname_list: ibswgt.views[tblname].setModel(ibswgt.models[tblname]) # Add Image, ANNOTATION, and Names as tabs for tblname in ibswgt.tblname_list: #ibswgt._table_tab_wgt.addTab(ibswgt.widgets[tblname], tblname) ibswgt._table_tab_wgt.addTab(ibswgt.views[tblname], tblname) # Custom ImageSet Tab Wiget ibswgt.imageset_tabwgt = ImagesetTabWidget(parent=ibswgt, horizontalStretch=19) # Other components ibswgt.outputLog = guitool.newOutputLog(ibswgt, pointSize=8, visible=WITH_GUILOG, verticalStretch=6) ibswgt.progressBar = guitool.newProgressBar(ibswgt, visible=False, verticalStretch=1) # New widget has black magic (for implicit layouts) in it ibswgt.status_wgt = guitool.newWidget(ibswgt, Qt.Vertical, verticalStretch=6, horizontalSizePolicy=QSizePolicy.Maximum) _NEWLBL = functools.partial(guitool.newLabel, ibswgt) _NEWBUT = functools.partial(guitool.newButton, ibswgt) # _COMBO = functools.partial(guitool.newComboBox, ibswgt) _NEWTEXT = functools.partial(guitool.newLineEdit, ibswgt, verticalStretch=1) primary_fontkw = dict(bold=True, pointSize=11) secondary_fontkw = dict(bold=False, pointSize=9) # advanced_fontkw = dict(bold=False, pointSize=8, italic=True) identify_color = (255, 150, 0) ibswgt.tablename_to_status_widget_index = { IMAGESET_TABLE: 1, IMAGE_TABLE: 3, IMAGE_GRID: 3, gh.ANNOTATION_TABLE: 5, NAMES_TREE: 7, NAME_TABLE: 7, } ibswgt.status_widget_list = [ _NEWLBL('Selected ImageSet: ', fontkw=secondary_fontkw, align='right'), _NEWTEXT(enabled=True, readOnly=True), ## _NEWLBL('Selected Image: ', fontkw=secondary_fontkw, align='right'), _NEWTEXT(enabled=True, readOnly=False, editingFinishedSlot=ibswgt.select_image_text_editing_finished), ## _NEWLBL('Selected Annotation: ', fontkw=secondary_fontkw, align='right'), _NEWTEXT(enabled=True, readOnly=False, editingFinishedSlot=ibswgt.select_annot_text_editing_finished), ## _NEWLBL('Selected Name: ', fontkw=secondary_fontkw, align='right'), _NEWTEXT(enabled=True, readOnly=False, editingFinishedSlot=ibswgt.select_name_text_editing_finished), ] back = ibswgt.back # detection_combo_box_options = [] # ibswgt.species_combo = _COMBO(detection_combo_box_options, # ibswgt.back.change_detection_species, # fontkw=primary_fontkw) # Define special intra-occurrence function # ibswgt.back.special_query_funcs['intra_occurrence'] = ut.overrideable_partial( ibswgt.batch_intra_occurrence_query_button = _NEWBUT( '4) ID Encounters', # ibswgt.back.special_query_funcs['intra_occurrence'], functools.partial( back.compute_queries, daids_mode=const.INTRA_OCCUR_KEY, query_is_known=None, use_prioritized_name_subset=False, cfgdict={'can_match_samename': False, 'use_k_padding': False} ), bgcolor=color_funcs.adjust_hsv_of_rgb255(identify_color, -0.01, -0.7, 0.0), fgcolor=(0, 0, 0), # fontkw=advanced_fontkw fontkw=primary_fontkw ) ibswgt.batch_vsexemplar_query_button = _NEWBUT( '5) ID Exemplars', functools.partial( back.compute_queries, daids_mode=const.VS_EXEMPLARS_KEY, use_prioritized_name_subset=True, query_is_known=None, cfgdict={'can_match_samename': False, 'use_k_padding': False}, ), bgcolor=color_funcs.adjust_hsv_of_rgb255(identify_color, -0.02, -0.7, 0.0), fgcolor=(0, 0, 0), # fontkw=advanced_fontkw fontkw=primary_fontkw ) # ibswgt.set_exemplars = _NEWBUT( # 'Set Exemplars', # back.set_exemplars_from_quality_and_viewpoint, # bgcolor=identify_color, # # bgcolor=color_funcs.adjust_hsv_of_rgb255(identify_color, -0.03, -0.7, 0.0), # fgcolor=(0, 0, 0), fontkw=advanced_fontkw) ibswgt.import_button = _NEWBUT( '1) Import', # back.import_images_from_dir, back.import_button_click, bgcolor=(235, 200, 200), fontkw=primary_fontkw) ibswgt.imageset_button = _NEWBUT( '2) Group', ibswgt.back.compute_occurrences, bgcolor=(255, 255, 150), fontkw=primary_fontkw) ibswgt.detect_button = _NEWBUT( '3) Detect', ibswgt.back.run_detection, bgcolor=(150, 255, 150), fontkw=primary_fontkw ) # ibswgt.inc_query_button = _NEWBUT( # 'Old Identify', # ibswgt.back.incremental_query, # bgcolor=identify_color, # fgcolor=(0, 0, 0), fontkw=primary_fontkw) # ibswgt.inc_query_button.setEnabled(False) #hack_enabled_machines = [ # 'ibeis.cs.uic.edu', # 'pachy.cs.uic.edu', # 'hyrule', #] #enable_complete = ut.get_computer_name() in hack_enabled_machines enable_complete = True ibswgt.reviewed_button = _NEWBUT( '6) Complete', ibswgt.back.imageset_reviewed_all_images, bgcolor=color_funcs.adjust_hsv_of_rgb255((0, 232, 211), 0., -.9, 0.), fontkw=primary_fontkw, enabled=enable_complete) ibswgt.control_widget_lists = [ [ ], [ ibswgt.import_button, ibswgt.imageset_button, _NEWLBL(''), ibswgt.detect_button, # _NEWLBL('ImageSet: ', align='right', fontkw=primary_fontkw), ibswgt.batch_intra_occurrence_query_button, ibswgt.batch_vsexemplar_query_button, ibswgt.reviewed_button, ], # [ # _NEWLBL('Species Selector: ', align='right', fontkw=primary_fontkw), # ibswgt.species_combo, # _NEWLBL(''), # _NEWLBL('*Advanced Batch Identification: ', align='right', fontkw=advanced_fontkw), # _NEWLBL('Identification: ', align='right', fontkw=advanced_fontkw), # _NEWLBL('Identification: ', align='right', fontkw=advanced_fontkw), # ibswgt.inc_query_button, # ibswgt.set_exemplars, # _NEWLBL(''), # ], ] def _init_layout(ibswgt): """ Lays out the defined components """ # Add elements to the layout ibswgt.vlayout.addWidget(ibswgt.imageset_tabwgt) ibswgt.vlayout.addWidget(ibswgt.vsplitter) ibswgt.vsplitter.addWidget(ibswgt.hsplitter) ibswgt.vsplitter.addWidget(ibswgt.status_wgt) # Horizontal Upper ibswgt.hsplitter.addWidget(ibswgt.views[IMAGESET_TABLE]) ibswgt.hsplitter.addWidget(ibswgt._table_tab_wgt) # Horizontal Lower ibswgt.status_wgt.addWidget(ibswgt.outputLog) ibswgt.status_wgt.addWidget(ibswgt.progressBar) # Add control widgets (import, group, species selector, etc...) ibswgt.control_layout_list = [] for control_widgets in ibswgt.control_widget_lists: ibswgt.control_layout_list.append(QtGui.QHBoxLayout(ibswgt)) ibswgt.status_wgt.addLayout(ibswgt.control_layout_list[-1]) for widget in control_widgets: ibswgt.control_layout_list[-1].addWidget(widget) # Add selected ids status widget ibswgt.selectionStatusLayout = QtGui.QHBoxLayout(ibswgt) ibswgt.status_wgt.addLayout(ibswgt.selectionStatusLayout) for widget in ibswgt.status_widget_list: ibswgt.selectionStatusLayout.addWidget(widget)
[docs] def changing_models_gen(ibswgt, tblnames=None): """ Loops over tablenames emitting layoutChanged at the end for each """ tblnames = ibswgt.super_tblname_list if tblnames is None else tblnames print('[newgui] changing_models_gen(tblnames=%r)' % (tblnames,)) model_list = [ibswgt.models[tblname] for tblname in tblnames] #model_list = [ibswgt.models[tblname] for tblname in tblnames if #ibswgt.views[tblname].isVisible()] with ChangeLayoutContext(model_list): for tblname in tblnames: yield tblname
[docs] def update_tables(ibswgt, tblnames=None, clear_view_selection=True): """ forces changing models """ print('[newgui] update_tables(%r)' % (tblnames,)) hack_selections = [] #print('[new_gui.UPDATE_TABLES]') for tblname in ibswgt.changing_models_gen(tblnames=tblnames): #print('[new_gui.update_tables] tblname=%r' % (tblname, )) model = ibswgt.models[tblname] view = ibswgt.views[tblname] if clear_view_selection: hack_selections.append(view.clearSelection) model._update() # Hack: Call this outside changing models gen for clearSelection in hack_selections: clearSelection()
[docs] def connect_ibeis_control(ibswgt, ibs): """ Connects a new ibscontroler to the models """ print('[newgui] connecting ibs control. ibs=%r' % (ibs,)) ibswgt.imageset_tabwgt._close_all_tabs() if ibs is None: print('[newgui] invalid ibs') title = 'No Database Opened' ibswgt.setWindowTitle(title) else: print('[newgui] Connecting valid ibs=%r' % ibs.get_dbname()) #with ut.Indenter('[CONNECTING]'): # Give the frontend the new control ibswgt.ibs = ibs with ut.Timer('update special'): if not ibs.readonly: ibs.update_special_imagesets() # Update the api models to use the new control with ut.Timer('make headers'): header_dict, declare_tup = gh.make_ibeis_headers_dict(ibswgt.ibs) ibswgt.declare_tup = declare_tup # Enable the redirections between tables #ibswgt._init_redirects() title = ibsfuncs.get_title(ibswgt.ibs) ibswgt.setWindowTitle(title) if ut.VERBOSE: print('[newgui] Calling model _update_headers') #block_wgt_flag = ibswgt._table_tab_wgt.blockSignals(True) with ut.Timer('[newgui] update models'): #for tblname in ibswgt.changing_models_gen(ibswgt.super_tblname_list): for tblname in ibswgt.super_tblname_list: model = ibswgt.models[tblname] view = ibswgt.views[tblname] #if not view.isVisible(): # print(view) #ut.embed() header = header_dict[tblname] #widget = ibswgt.widgets[tblname] #widget.change_headers(header) # # NOT SURE IF THESE BLOCKERS SHOULD BE COMMENTED #block_model_flag = model.blockSignals(True) model._update_headers(**header) view._update_headers(**header) # should use model headers #model.blockSignals(block_model_flag) # #view.infer_delegates_from_model() for tblname in ibswgt.super_tblname_list: view = ibswgt.views[tblname] #if not view.isVisible(): # print(view) # continue view.hide_cols() #ibswgt._table_tab_wgt.blockSignals(block_wgt_flag) # FIXME: bad code # TODO: load previously loaded imageset or nothing LOAD_IMAGESET_ON_START = True if LOAD_IMAGESET_ON_START: imgsetid_list = ibs.get_valid_imgsetids(shipped=False) if len(imgsetid_list) > 0: DEFAULT_LARGEST_IMAGESET = False if DEFAULT_LARGEST_IMAGESET: numImg_list = ibs.get_imageset_num_gids(imgsetid_list) argx = ut.list_argsort(numImg_list)[-1] imgsetid = imgsetid_list[argx] else: # Grab "first" imageset imgsetid = imgsetid_list[0] #ibswgt._change_imageset(imgsetid) ibswgt.select_imageset_tab(imgsetid) else: ibswgt._change_imageset(-1) # Update species with ones enabled in database if not ibs.readonly: ibswgt.update_species_available()
[docs] def update_species_available(ibswgt, reselect=False, reselect_new_name=None, deleting=False): ibs = ibswgt.ibs # TODO: update these options depending on ibs.get_species_with_detectors # when a controller is attached to the gui detection_combo_box_options = [ # Text # Value #('Select Species', 'none'), ('Select Species', const.UNKNOWN), ('Unknown', const.UNKNOWN), #'none'), ] + sorted(list(ibs.get_working_species())) species_text = ibswgt.back.get_selected_species() reselect_index = None if not deleting and reselect_new_name is None and species_text is not None: species_rowid = ibs.get_species_rowids_from_text(species_text) reselect_new_name = ibs.get_species_nice(species_rowid) print('[update_species_available] Reselecting old selection: %r' % (reselect_new_name, )) nice_name_list = [ str(_[0]) for _ in detection_combo_box_options ] if reselect_new_name in nice_name_list: reselect_index = nice_name_list.index(reselect_new_name) print('[update_species_available] Reselecting renamed selection: %r' % (reselect_new_name, )) print('[update_species_available] Reselecting index: %r' % (reselect_index, )) # ibswgt.species_combo.setOptions(detection_combo_box_options) # ibswgt.species_combo.updateOptions(reselect=reselect, reselect_index=reselect_index)
[docs] def setWindowTitle(ibswgt, title): parent_ = ibswgt.parent() if parent_ is not None: parent_.setWindowTitle(title) else: IBEIS_WIDGET_BASE.setWindowTitle(ibswgt, title)
def _change_imageset(ibswgt, imgsetid): print('[newgui] _change_imageset(imgsetid=%r, uuid=%r)' % (imgsetid, ibswgt.back.ibs.get_imageset_uuid(imgsetid))) for tblname in ibswgt.tblname_list: view = ibswgt.views[tblname] view.clearSelection() for tblname in ibswgt.changing_models_gen(tblnames=ibswgt.tblname_list): view = ibswgt.views[tblname] view._change_imageset(imgsetid) #ibswgt.models[tblname]._change_imageset(imgsetid) # the view should take care of this call try: #if imgsetid is None: # # HACK # imagesettext = const.ALL_IMAGE_IMAGESETTEXT #else: # imagesettext = ibswgt.ibs.get_imageset_text(imgsetid) ibswgt.back.select_imgsetid(imgsetid) # ibswgt.species_combo.setDefault(ibswgt.ibs.cfg.detect_cfg.species_text) #text_list = [ # 'Identify Mode: Within-ImageSet (%s vs. %s)' % (imagesettext, imagesettext), # 'Identify Mode: Exemplars (%s vs. %s)' % (imagesettext, const.EXEMPLAR_IMAGESETTEXT)] #text_list = [ # 'Identify Mode: Within-ImageSet' , # 'Identify Mode: Exemplars'] #query_text = #ibswgt.query_button #ibswgt.querydb_combo.setOptionText(text_list) #ibswgt.query_ #ibswgt.control_widget_lists[1][0].setText('Identify #(intra-imageset)\nQUERY(%r vs. %r)' % (imagesettext, imagesettext)) #ibswgt.control_widget_lists[1][1].setText('Identify (vs exemplar #database)\nQUERY(%r vs. %r)' % (imagesettext, const.EXEMPLAR_IMAGESETTEXT)) except Exception as ex: ut.printex(ex, iswarning=True) ibswgt.set_table_tab(IMAGE_TABLE) def _update_imageset_tab_name(ibswgt, imgsetid, imagesettext): ibswgt.imageset_tabwgt._update_imageset_tab_name(imgsetid, imagesettext) #------------ # SLOT HELPERS #------------
[docs] def get_table_tab_index(ibswgt, tblname): view = ibswgt.views[tblname] index = ibswgt._table_tab_wgt.indexOf(view) return index
[docs] def set_status_text(ibswgt, key, text): #printDBG('set_status_text[%r] = %r' % (index, text)) index = ibswgt.tablename_to_status_widget_index[key] ibswgt.status_widget_list[index].setText(text)
[docs] def set_table_tab(ibswgt, tblname): """ Programmatically change to the table-tab to either: Image, ImageGrid, Annotation, or Names table/tree Example: >>> # GUI_DOCTEST >>> from ibeis.gui.newgui import * # NOQA >>> # build test data >>> ibs, back, ibswgt, testdata_main_loop = testdata_guifront() >>> ibswgt.set_table_tab(gh.ANNOTATION_TABLE) """ print('[newgui] set_table_tab: %r ' % (tblname,)) index = ibswgt.get_table_tab_index(tblname) ibswgt._table_tab_wgt.setCurrentIndex(index)
[docs] def select_imageset_tab(ibswgt, imgsetid): if False: prefix = ut.get_caller_name(range(0, 10)) prefix = prefix.replace('[wrp_noexectb]', 'w') prefix = prefix.replace('[slot_wrapper]', 's') prefix = prefix.replace('[X]', 'x') else: prefix = '' print(prefix + '[newgui] select_imageset_tab imgsetid=%r' % (imgsetid,)) if isinstance(imgsetid, six.string_types): # Hack imagesettext = imgsetid imgsetid = ibswgt.ibs.get_imageset_imgsetids_from_text(imagesettext) else: imagesettext = ibswgt.ibs.get_imageset_text(imgsetid) #ibswgt.back.select_imgsetid(imgsetid) ibswgt.imageset_tabwgt._add_imageset_tab(imgsetid, imagesettext)
[docs] def spawn_edit_image_annotation_interaction_from_aid(ibswgt, aid, imgsetid, model=None, qtindex=None): """ hack for letting annots spawn image editing CommandLine: python -m ibeis.gui.newgui --test-spawn_edit_image_annotation_interaction_from_aid --show Example: >>> # DISABLE_DOCTEST >>> from ibeis.gui.newgui import * # NOQA >>> import ibeis >>> main_locals = ibeis.main(defaultdb='testdb1') >>> ibs, back = ut.dict_take(main_locals, ['ibs', 'back']) >>> ibswgt = back.ibswgt # NOQA >>> aid = 4 >>> imgsetid = 1 >>> ibswgt.spawn_edit_image_annotation_interaction_from_aid(aid, imgsetid) >>> if ut.show_was_requested(): >>> guitool.qtapp_loop(qwin=ibswgt) """ gid = ibswgt.back.ibs.get_annot_gids(aid) if model is None: view = ibswgt.views[IMAGE_TABLE] model = view.model() qtindex, row = view.get_row_and_qtindex_from_id(gid) ibswgt.spawn_edit_image_annotation_interaction(model, qtindex, gid, imgsetid)
[docs] def spawn_edit_image_annotation_interaction(ibswgt, model, qtindex, gid, imgsetid): """ TODO: needs reimplement using more standard interaction methods """ print('[newgui] Creating new annotation interaction: gid=%r' % (gid,)) ibs = ibswgt.ibs # Select gid ibswgt.back.select_gid(gid, imgsetid, show=False) # Interact with gid nextcb, prevcb, current_gid = ibswgt._interactannot2_callbacks(model, qtindex) iannot2_kw = { 'rows_updated_callback': ibswgt.update_tables, 'next_callback': nextcb, 'prev_callback': prevcb, } assert current_gid == gid, 'problem in next/prev updater' ibswgt.annot_interact = interact_annotations2.ANNOTATION_Interaction2( ibs, gid, **iannot2_kw) # hacky GID_PROG: TODO: FIX WITH OTHER HACKS OF THIS TYPE # FIXME; this should depend on the model. #_, row = model.view.get_row_and_qtindex_from_id(gid) #pt.set_figtitle('%d/%d' % (row + 1, model.rowCount())) level_num_rows = model._get_level_row_count(qtindex) level_row = model._get_level_row_index(qtindex) pt.set_figtitle('%d/%d' % (level_row + 1, level_num_rows))
[docs] def make_adjacent_qtindex_callbacks(ibswgt, model, qtindex): r""" Returns: tuple: (current_rowid, next_callback, prev_callback) CommandLine: python -m ibeis.gui.newgui --test-make_adjacent_qtindex_callbacks Example: >>> # DISABLE_DOCTEST >>> from ibeis.gui.newgui import * # NOQA >>> # build test data >>> ibs, back, ibswgt, testdata_main_loop = testdata_guifront() >>> gid = ibs.get_valid_gids()[0] >>> model = ibswgt.models[gh.IMAGE_TABLE] >>> qtindex, row = model.get_row_and_qtindex_from_id(gid) >>> # execute function >>> (current_rowid, next_callback, prev_callback) = ibswgt.make_adjacent_qtindex_callbacks(model, qtindex) >>> assert prev_callback is None, 'should not be a previous image id' >>> current_rowid1, next_callback1, prev_callback1 = next_callback() >>> assert next_callback() is None, 'race condition not prevented' >>> current_rowid2, next_callback2, prev_callback2 = next_callback1() >>> # testdata main loop func >>> testdata_main_loop(globals(), locals()) """ current_rowid = model._get_row_id(qtindex) next_qtindex = model._get_adjacent_qtindex(qtindex, 1) prev_qtindex = model._get_adjacent_qtindex(qtindex, -1) next_callback = None prev_callback = None numclicks = [0] # semephore, invalidates both functions after one call if next_qtindex is not None and next_qtindex.isValid(): def next_callback(): if numclicks[0] != 0: print('race condition in next_callback %d ' % numclicks[0]) return numclicks[0] += 1 return ibswgt.make_adjacent_qtindex_callbacks(model, next_qtindex) if prev_qtindex is not None and prev_qtindex.isValid(): def prev_callback(): if numclicks[0] != 0: print('race condition in next_callback %d ' % numclicks[0]) return numclicks[0] += 1 return ibswgt.make_adjacent_qtindex_callbacks(model, next_qtindex) return current_rowid, next_callback, prev_callback
def _interactannot2_callbacks(ibswgt, model, qtindex): """ callbacks for the edit image annotation (from image table) interaction python -m ibeis --db lynx --imgsetid 2 TODO: needs reimplement """ #if not qtindex.isValid(): # raise AssertionError('Bug: qtindex got invalidated') # # BUG: somewhere qtindex gets invalidated # #return None, None, -1 # HACK FOR NEXT AND PREVIOUS CLICK CALLBACKS #print('model.name = %r' % (model.name,)) if model.name == gh.IMAGE_TABLE: cur_gid = model._get_row_id(qtindex) # elif model.name == gh.IMAGE_GRID: # cur_gid = model._get_row_id(qtindex) elif model.name == gh.NAMES_TREE: cur_level = model._get_level(qtindex) if cur_level == 1: cur_aid = model._get_row_id(qtindex) cur_gid = ibswgt.ibs.get_annot_gids(cur_aid) else: raise NotImplementedError('Unknown model.name=%r, cur_level=%r' % (model.name, cur_level)) else: print('gh.IMAGE_TABLE = %r' % (gh.IMAGE_TABLE,)) raise NotImplementedError('Unknown model.name =%r' % (model.name,)) next_qtindex = model._get_adjacent_qtindex(qtindex, 1) prev_qtindex = model._get_adjacent_qtindex(qtindex, -1) numclicks = [0] # semephore def make_qtindex_callback(qtindex_, type_='nextprev'): def _qtindex_callback(): if numclicks[0] != 0: print('race condition in %s_callback %d ' % (type_, numclicks[0])) return numclicks[0] += 1 # call this function again with next index nextcb, prevcb, new_gid1 = ibswgt._interactannot2_callbacks(model, qtindex_) print('[newgui] %s_callback: new_gid1=%r' % (type_, new_gid1)) ibswgt.annot_interact.update_image_and_callbacks( new_gid1, nextcb, prevcb, do_save=True) # hacky GID_PROG: TODO: FIX WITH OTHER HACKS OF THIS TYPE #_, row = model.view.get_row_and_qtindex_from_id(new_gid1) #pt.set_figtitle('%d/%d' % (row + 1, model.rowCount())) level_num_rows = model._get_level_row_count(qtindex_) level_row = model._get_level_row_index(qtindex_) pt.set_figtitle('%d/%d' % (level_row + 1, level_num_rows)) return _qtindex_callback if next_qtindex is not None and next_qtindex.isValid(): next_callback = make_qtindex_callback(next_qtindex, 'next') else: next_callback = None if prev_qtindex is not None and prev_qtindex.isValid(): prev_callback = make_qtindex_callback(prev_qtindex, 'prev') else: prev_callback = None return next_callback, prev_callback, cur_gid #------------ # SLOTS #------------ @slot_(str)
[docs] def select_annot_text_editing_finished(ibswgt): tablename = gh.ANNOTATION_TABLE index = ibswgt.tablename_to_status_widget_index[tablename] text = ibswgt.status_widget_list[index].text() ibswgt.select_table_indicies_from_text(tablename, text)
@slot_(str)
[docs] def select_name_text_editing_finished(ibswgt): tablename = gh.NAMES_TREE index = ibswgt.tablename_to_status_widget_index[tablename] text = ibswgt.status_widget_list[index].text() ibswgt.select_table_indicies_from_text(tablename, text)
@slot_(str)
[docs] def select_image_text_editing_finished(ibswgt): tablename = gh.IMAGE_TABLE index = ibswgt.tablename_to_status_widget_index[tablename] text = ibswgt.status_widget_list[index].text() ibswgt.select_table_indicies_from_text(tablename, text)
[docs] def select_table_indicies_from_text(ibswgt, tblname, text, allow_table_change=False): """ Args: tblname - tablename of the id to parse from text Ignore: text = '[1, 2, 3,]' text = '51e10019-968b-5f2e-2287-8432464d7547 ' Example: >>> # GUI_DOCTEST >>> from ibeis.gui.newgui import * # NOQA >>> # build test data >>> ibs, back, ibswgt, testdata_main_loop = testdata_guifront() >>> ibswgt.set_table_tab(gh.ANNOTATION_TABLE) >>> tblname = gh.NAMES_TREE >>> text = 'lena' >>> ibswgt.select_table_indicies_from_text(tblname, text) """ if not ut.QUIET: print('[newgui] select_table_indicies_from_text') print('[newgui] * gh.tblname = %r' % (tblname,)) print('[newgui] * text = %r' % (text,)) to_backend_tablename = { gh.ANNOTATION_TABLE : const.ANNOTATION_TABLE, gh.NAMES_TREE : const.NAME_TABLE, gh.IMAGE_TABLE : const.IMAGE_TABLE, } backend_tablename = to_backend_tablename[tblname] if not ut.QUIET: print('[newgui] * backend_tablename = %r' % (backend_tablename,)) if text == '': text = '[]' try: #MODE1 = True #if MODE1: id_list_ = text.lstrip('[').rstrip(']').split(',') id_list = [id_.strip() for id_ in id_list_] id_list = [id_ for id_ in id_list if len(id_) > 0] try: id_list = list(map(int, id_list)) except ValueError: import uuid try: # First check to see if the text is a UUID id_list = list(map(uuid.UUID, id_list)) except ValueError: if tblname != gh.NAMES_TREE: raise else: # then maybe it was a name that was selected id_list = list(map(str, id_list)) #else: # id_list_ = eval(text, globals(), locals()) # id_list = ut.ensure_iterable(id_list_) # NOQA except Exception as ex: ut.printex(ex, iswarning=True, keys=['text']) else: if not ut.QUIET: print('[newgui] * id_list = %r' % (id_list,)) #print(id_list) id_list = ibswgt.back._set_selection3(backend_tablename, id_list, mode='set') # Select the index if we are in the right table tab if len(id_list) == 1 and ( allow_table_change or ibswgt._table_tab_wgt.current_tblname == tblname): if not ut.QUIET: print('[newgui] * attempting to select from rowid') #view = ibswgt.views[tblname] #view.select_row_from_id(id_list[0]) ibswgt.goto_table_id(tblname, id_list[0]) else: # TODO: convert the id into the ids corresponding with this tablename and move # to the first one pass ibswgt.back.update_selection_texts() #pass
@slot_(str, int)
[docs] def on_rows_updated(ibswgt, tblname, nRows): """ When the rows are updated change the tab names """ if VERBOSE_GUI: print('[newgui] on_rows_updated: tblname=%12r nRows=%r ' % (tblname, nRows)) #printDBG('Rows updated in tblname=%r, nRows=%r' % (str(tblname), nRows)) if tblname == IMAGESET_TABLE: # Hack print('... tblname == IMAGESET_TABLE, ...hack return') return tblname = str(tblname) TABLE_NICE = ibswgt.declare_tup[1] # hack tblnice = TABLE_NICE[tblname] index = ibswgt.get_table_tab_index(tblname) text = tblnice + ' ' + str(nRows) #printDBG('Rows updated in index=%r, text=%r' % (index, text)) # CHANGE TAB NAME TO SHOW NUMBER OF ROWS ibswgt._table_tab_wgt.setTabText(index, text)
[docs] def goto_table_id(ibswgt, tablename, _id): print('[newgui] goto_table_id(tablenamd=%r, _id=%r)' % (tablename, _id)) ibswgt.set_table_tab(tablename) view = ibswgt.views[tablename] view.select_row_from_id(_id, scroll=True)
@slot_(QtCore.QModelIndex, QtCore.QPoint)
[docs] def on_contextMenuClicked(ibswgt, qtindex, pos): """ Right click anywhere in the GUI Context menus on right click of a table CommandLine: python -m ibeis --db WS_ALL --imgsetid 2 --select-name=A-003 """ if not qtindex.isValid(): return #printDBG('[newgui] contextmenu') model = qtindex.model() tblview = ibswgt.views[model.name] context_options = [] qtindex_list = tblview.selectedIndexes() id_list = [model._get_row_id(_qtindex) for _qtindex in qtindex_list] level_list = [model._get_level(_qtindex) for _qtindex in qtindex_list] level2_ids_ = ut.group_items(id_list, level_list) level2_ids = {level: ut.unique_ordered(ids) for level, ids in six.iteritems(level2_ids_)} ibs = ibswgt.back.ibs back = ibswgt.back def build_annot_context_options(ibswgt, ibs, aid_list, imgsetid, **kwargs): context_options = [] if len(aid_list) == 1: aid = aid_list[0] if kwargs.get('goto_image', True): context_options += [ ('Go to image', lambda: ibswgt.goto_table_id(IMAGE_TABLE, ibswgt.back.ibs.get_annot_gids(aid)),) ] if kwargs.get('goto_annot', True): context_options += [ ('Go to annot', lambda: ibswgt.goto_table_id(gh.ANNOTATION_TABLE, aid)) ] if kwargs.get('goto_name', True): context_options += [ ('Go to name', lambda: ibswgt.goto_table_id(NAMES_TREE, ibswgt.back.ibs.get_annot_nids(aid))), ] if kwargs.get('canedit', True): context_options += [ ('Edit Annotation in Image', lambda: ibswgt.spawn_edit_image_annotation_interaction_from_aid(aid, imgsetid)), ] context_options += [ ('----', lambda: None), ('View annotation in Web', #lambda: ibswgt.back.select_aid(aid, imgsetid, show=True)), lambda: ibswgt.back.show_annotation(aid, web=True)), ('View image in Web', lambda: ibswgt.back.select_gid_from_aid(aid, imgsetid, show=True, web=True)), ('----', lambda: None), ('Remove annotation\'s name', lambda: ibswgt.back.unset_names([aid])), ('Delete annotation', lambda: ibswgt.back.delete_annot(aid_list)), ('----', lambda: None), ] from ibeis.viz.interact import interact_chip from ibeis import viz context_options += interact_chip.build_annot_context_options( ibswgt.back.ibs, aid, refresh_func=viz.draw, with_interact_image=False) else: context_options += [ ('View annotations in Web', lambda: ibswgt.back.show_aid_list_in_web(aid_list)), ('Unset annotations\' names', lambda: ibswgt.back.unset_names(aid_list)), ('Delete annotations', lambda: ibswgt.back.delete_annot(aid_list)), ] return context_options def name_context_options(ibswgt, ibs, nid_list, aid_list, imgsetid, **kwargs): context_options = [] if len(aid_list) == 1: aid = aid_list[0] context_options += build_annot_context_options(ibswgt, ibs, [aid], imgsetid) if len(aid_list) > 0: def set_annot_names_to_same_new_name(ibswgt, aid_list): ibswgt.back.ibs.set_annot_names_to_same_new_name(aid_list) ibswgt.update_tables(tblnames=[gh.NAMES_TREE]) context_options += [ ('Rename annots (%s) to new name' % ut.list_str_summarized( aid_list, 'aid_list'), lambda: set_annot_names_to_same_new_name(ibswgt, aid_list)), ] if len(nid_list) > 0: def run_splits(ibs, nid_list): print('Checking for splits') aids_list = ibs.get_name_aids(nid_list) aid_list = sorted(list(set(ut.flatten(aids_list)))) back.run_annot_splits(aid_list) def export_nids(ibs, nid_list): from ibeis.dbio import export_subset if not back.are_you_sure('Confirm export of nid_list=%r' % (nid_list,)): return export_subset.export_names(ibs, nid_list) def create_new_imageset_from_names_(ibs, nid_list): ibs.create_new_imageset_from_names(nid_list) ibswgt.update_tables([gh.IMAGESET_TABLE], clear_view_selection=False) context_options += [ ('View name(s) in Web', lambda: ibswgt.back.show_nid_list_in_web(nid_list)), ('----', lambda: None), ('Check for splits', lambda: run_splits(ibs, nid_list)), ('Export names', lambda: export_nids(ibs, nid_list)), ('Create ImageSet From Name(s)', lambda: create_new_imageset_from_names_(ibs, nid_list)), ] from ibeis.viz.interact import interact_name context_options += interact_name.build_name_context_options( ibswgt.back.ibs, nid_list) else: from ibeis.viz.interact import interact_name context_options += interact_name.build_name_context_options( ibswgt.back.ibs, nid_list) #print('nutin') pass return context_options def build_image_context_options(ibswgt, ibs, gid_list, imgsetid, **kwargs): current_imagesettext = ibswgt.back.ibs.get_imageset_text(imgsetid) context_options = [] # Conditional context menu context_options = [ ('Edit image ' + ut.pluralize('time', len(gid_list)), lambda: ibswgt.edit_image_time([gid])) ] if len(gid_list) == 1: gid = gid_list[0] imgsetid = model.imgsetid aid_list = ibs.get_image_aids(gid) annot_options = [ ('Options aid=%r' % (aid,), build_annot_context_options(ibswgt, ibs, [aid], imgsetid, goto_image=False)) for aid in aid_list ] if len(aid_list) == 1: annot_option_item = ( 'Annot Options (aid=%r)' % (aid_list[0],), annot_options[0][1] ) else: annot_option_item = ('Annot Options', annot_options) if kwargs.get('goto_image_in_imgtbl', False): context_options += [ ('Go to image in Images Table', lambda: ibswgt.goto_table_id(IMAGE_TABLE, gid)), ] context_options += [ ('View image in Matplotlib', lambda: ibswgt.back.select_gid(gid, imgsetid, show=True, web=False)), ('View image in Web', lambda: ibswgt.back.select_gid(gid, imgsetid, show=True, web=True)), ('View detection image (Hough) [dev]', lambda: ibswgt.back.show_hough_image(gid)), annot_option_item, #('View annotation in Matplotlib:', # view_aid_options1), #('View annotation in Web:', # view_aid_options2), ('Add annotation from entire image', lambda: ibswgt.back.add_annotation_from_image([gid])), ('Run detection on image (can cause duplicates)', lambda: ibswgt.back.run_detection_on_images([gid])), ] else: context_options += [ ('View images in Web', lambda: ibswgt.back.show_gid_list_in_web(gid_list)), ('----', lambda: None), ('Add annotation from entire images', lambda: ibswgt.back.add_annotation_from_image(gid_list)), ('Run detection on images (can cause duplicates)', lambda: ibswgt.back.run_detection_on_images(gid_list)), ] # Special condition for imagesets if current_imagesettext != const.NEW_IMAGESET_IMAGESETTEXT: context_options += [ ('----', lambda: None), ('Move to new imageset', lambda: ibswgt.back.send_to_new_imageset(gid_list, mode='move')), ('Copy to new imageset', lambda: ibswgt.back.send_to_new_imageset(gid_list, mode='copy')), ] if current_imagesettext != const.UNGROUPED_IMAGES_IMAGESETTEXT: context_options += [ ('----', lambda: None), ('Remove from imageset', lambda: ibswgt.back.remove_from_imageset(gid_list)), ] # Continue the conditional context menu if len(gid_list) == 1: # We get gid from above context_options += [ ('----', lambda: None), ('Delete image\'s annotations', lambda: ibswgt.back.delete_image_annotations([gid])), ('Delete image', lambda: ibswgt.back.delete_image(gid)), ] else: context_options += [ ('----', lambda: None), ('Delete images\' annotations', lambda: ibswgt.back.delete_image_annotations(gid_list)), ('Delete images', lambda: ibswgt.back.delete_image(gid_list)), ] return context_options # ---- IMAGESET CONTEXT ---- if model.name == IMAGESET_TABLE: # This is for the benefit of merge imagesets merge_destination_id = model._get_row_id(qtindex) imagesettext = ibswgt.back.ibs.get_imageset_text(merge_destination_id) imgsetid_list = level2_ids[0] # Conditional context menu # TODO: remove duplicate code if len(imgsetid_list) == 1: context_options += [ ('View imageset in Web', lambda: ibswgt.back.show_imgsetid_list_in_web(imgsetid_list)), ('----', lambda: None), ('Run detection on imageset (can cause duplicates)', lambda: ibswgt.back.run_detection_on_imageset(imgsetid_list)), ('Merge %d imageset into %s' % (len(imgsetid_list), (imagesettext)), lambda: ibswgt.back.merge_imagesets(imgsetid_list, merge_destination_id)), ('Copy imageset', lambda: ibswgt.back.copy_imageset(imgsetid_list)), ('Export imageset', lambda: ibswgt.back.export_imagesets(imgsetid_list)), ('----', lambda: None), ('Delete imageset', lambda: ibswgt.back.delete_imageset(imgsetid_list)), ('----', lambda: None), ('Delete imageset AND images', lambda: ibswgt.back.delete_imageset_and_images(imgsetid_list)), ] else: context_options += [ ('Run detection on imagesets (can cause duplicates)', lambda: ibswgt.back.run_detection_on_imageset(imgsetid_list)), ('Copy imageset', lambda: ibswgt.back.copy_imageset(imgsetid_list)), ('Merge %d imagesets into %s' % (len(imgsetid_list), (imagesettext)), lambda: ibswgt.back.merge_imagesets(imgsetid_list, merge_destination_id)), ('----', lambda: None), ('Delete imagesets', lambda: ibswgt.back.delete_imageset(imgsetid_list)), ('----', lambda: None), ('Delete imagesets AND images', lambda: ibswgt.back.delete_imageset_and_images(imgsetid_list)), # ('export imagesets', lambda: ibswgt.back.export_imagesets(imgsetid_list)), ] # ---- IMAGE CONTEXT ---- elif model.name == IMAGE_TABLE: gid_list = level2_ids[0] imgsetid = ibswgt.back.get_selected_imgsetid() context_options += build_image_context_options(ibswgt, ibs, gid_list, imgsetid) # ---- IMAGE GRID CONTEXT ---- elif model.name == IMAGE_GRID: gid_list = level2_ids[0] imgsetid = ibswgt.back.get_selected_imgsetid() context_options += build_image_context_options(ibswgt, ibs, gid_list, imgsetid, goto_image_in_imgtbl=True) # ---- ANNOTATION CONTEXT ---- elif model.name == gh.ANNOTATION_TABLE: aid_list = level2_ids[0] # Conditional context menu # TODO: UNIFY COMMMON CONTEXT MENUS context_options += build_annot_context_options( ibswgt, ibs, aid_list, model.imgsetid, goto_annot=False) # ---- NAMES TREE CONTEXT ---- elif model.name == NAMES_TREE: # TODO: map level list to tablename more reliably ut.print_dict(level2_ids) nid_list = level2_ids.get(0, []) aid_list = level2_ids.get(1, []) if len(aid_list) > 0 and len(nid_list) > 0: # two types of indices are selected, just return # fixme to do something useful print('multiple types of indicies selected') return else: imgsetid = model.imgsetid context_options += name_context_options(ibswgt, ibs, nid_list, aid_list, imgsetid) # Show the context menu #ut.print_list(context_options, nl=2) if len(context_options) > 0: guitool.popup_menu(tblview, pos, context_options)
@slot_(QtCore.QModelIndex)
[docs] def on_doubleclick(ibswgt, qtindex): """ Double clicking anywhere in the GUI CommandLine: python -m ibeis --db lynx --imgsetid 2 --select-name=goku """ print('\n+--- DOUBLE CLICK ---') if not qtindex.isValid(): print('[doubleclick] invalid qtindex') return #printDBG('on_doubleclick') model = qtindex.model() id_ = model._get_row_id(qtindex) if model.name == IMAGESET_TABLE: imgsetid = id_ ibswgt.select_imageset_tab(imgsetid) else: imgsetid = model.imgsetid if (model.name == IMAGE_TABLE) or (model.name == IMAGE_GRID): gid = id_ ibswgt.spawn_edit_image_annotation_interaction(model, qtindex, gid, imgsetid) elif model.name == gh.ANNOTATION_TABLE: aid = id_ ibswgt.back.select_aid(aid, imgsetid) elif model.name == NAME_TABLE: nid = id_ ibswgt.back.select_nid(nid, imgsetid) elif model.name == NAMES_TREE: level = model._get_level(qtindex) if level == 0: nid = id_ ibswgt.back.select_nid(nid, imgsetid, show=True) elif level == 1: aid = id_ ibswgt.spawn_edit_image_annotation_interaction_from_aid(aid, imgsetid, model, qtindex) #ibswgt.back.select_aid(aid, imgsetid, show=True) # @slot_(list)
[docs] def imagesDropped(ibswgt, url_list): r""" image drag and drop event CommandLine: python -m ibeis.gui.newgui imagesDropped --show Example: >>> # GUI_DOCTEST >>> from ibeis.gui.newgui import * # NOQA >>> ibs, back, ibswgt, testdata_main_loop = testdata_guifront('hstest') >>> url_list = ['images.foo'] >>> url_list = [ut.truepath('~/Downloads/hs-images.zip')] >>> url = url_list[0] >>> ut.quit_if_noshow() >>> ibswgt.imagesDropped(url_list) >>> testdata_main_loop(globals(), locals()) """ print('[drop_event] url_list=%r' % (url_list,)) has_zipext = ut.partial(ut.fpath_has_ext, exts=['.zip']) gpath_list = list(filter(ut.fpath_has_imgext, url_list)) dir_list = list(filter(isdir, url_list)) zipfile_list = list(filter(has_zipext, url_list)) old = False if old: if len(dir_list) > 0: options = ['No', 'Yes'] title = 'Non-Images dropped' msg = 'Recursively import from directories?' ans = guitool.user_option(ibswgt, msg=msg, title=title, options=options) if ans == 'Yes': unflat_gpaths = [ut.list_images(dir_, fullpath=True, recursive=True) for dir_ in dir_list] flat_gpaths = ut.flatten(unflat_gpaths) flat_unix_gpaths = list(map(ut.unixpath, flat_gpaths)) gpath_list.extend(flat_unix_gpaths) else: return print('[drop_event] gpath_list=%r' % (gpath_list,)) if len(gpath_list) > 0: ibswgt.back.import_images_from_file(gpath_list=gpath_list) else: from ibeis.dbio import ingest_database ibs = ibswgt.back.ibs ingestable = ingest_database.Ingestable2( ibs.get_dbdir(), gpath_list, dir_list, zipfile_list) num_gpaths = len(ingestable.imgpath_list) num_dpaths = len(ingestable.imgdir_list) num_zips = len(ingestable.zipfile_list) confirm_list = [] if num_gpaths > 0: confirm_list += [ut.quantstr('image file', num_gpaths)] if num_dpaths > 0: confirm_list += ['recursively from ' + ut.quantstr('directory', num_dpaths, 's')] if num_zips > 0: confirm_list += [ut.quantstr('zip file', num_zips, 's')] confirm_msg = 'Import from: ' + ut.conj_phrase(confirm_list, 'and') + '.' # guitool.rrrr() config = ingestable.ingest_config # cfg = config dlg = guitool.ConfigConfirmWidget.as_dialog(ibswgt, title='Confirm Import Images', msg=confirm_msg, config=config) dlg.resize(700, 500) self = dlg.widget dlg.exec_() print('config = %r' % (config,)) updated_config = self.config # NOQA print('updated_config = %r' % (updated_config,)) gid_list = ingestable.execute(ibs=ibs) ibswgt.back._process_new_images(refresh=True, gid_list=gid_list, clock_offset=False)
[docs] def register_redirect(ibswgt, src_table, src_table_col, dst_table, mapping_func): if src_table not in ibswgt.redirects.keys(): ibswgt.redirects[src_table] = {} ibswgt.redirects[src_table][src_table_col] = (dst_table, mapping_func)
[docs] def select_table_id(ibswgt, table_key, level, id_, imgsetid): select_func_dict = { (IMAGE_TABLE, 0) : ibswgt.back.select_gid, (IMAGE_GRID, 0) : ibswgt.back.select_gid, (gh.ANNOTATION_TABLE, 0) : ibswgt.back.select_aid, (NAME_TABLE, 0) : ibswgt.back.select_nid, (NAMES_TREE, 0) : ibswgt.back.select_nid, (NAMES_TREE, 1) : ibswgt.back.select_aid, } select_func = select_func_dict[(table_key, level)] select_func(id_, imgsetid, show=False)
[docs] def edit_image_time(ibswgt, gid_list): """ CommandLine: python -m ibeis.gui.newgui --exec-edit_image_time --show Example: >>> # DISABLE_DOCTEST >>> from ibeis.gui.newgui import * # NOQA >>> ibs, back, ibswgt, testdata_main_loop = testdata_guifront('testdb3') >>> #ibs, back, ibswgt, testdata_main_loop = testdata_guifront('lynx') >>> ibswgt.edit_image_time([277, 630]) >>> testdata_main_loop(globals(), locals()) """ from ibeis.gui import clock_offset_gui ibswgt.co_wgt = clock_offset_gui.ClockOffsetWidget(ibswgt.ibs, gid_list, hack=True) ibswgt.co_wgt.show()
[docs] def filter_annotation_table(ibswgt): r""" TODO: Finish implementation CommandLine: python -m ibeis.gui.newgui --test-filter_annotation_table --show --db lynx --imgsetid 2 Example: >>> # DISABLE_DOCTEST >>> from ibeis.gui.newgui import * # NOQA >>> ibs, back, ibswgt, testdata_main_loop = testdata_guifront('testdb3') >>> #ibs, back, ibswgt, testdata_main_loop = testdata_guifront('PZ_Master1') >>> result = ibswgt.filter_annotation_table() >>> print(result) >>> testdata_main_loop(globals(), locals()) """ from functools import partial #ibs.filter_annots_general() ibs = ibswgt.back.ibs #ibs.filterannots_by_tags(aid_list) print('\n------FILTERING ANNOTS\n\n') #annotmatch_rowid_list = ibs._get_all_annotmatch_rowids() #isscenerymatch_list = ibs.get_annotmatch_is_scenerymatch(annotmatch_rowid_list) #ut.take(isscenerymatch_list, ut.list_where(isscenerymatch_list)) # Applies annotation based filtering to the annotation table #filter_kw = dict(any_matches='.*error.*', been_adjusted=True) filter_kw = dict(been_adjusted=True) #filter_kw = dict(require_timestamp=True) filter_fn = partial(ibs.filter_annots_general, filter_kw=filter_kw) model = ibswgt.models[gh.ANNOTATION_TABLE] # NOQA model.set_ider_filters([filter_fn]) with ChangeLayoutContext([model]): model._update_rows(rebuild_structure=True) ###################### ###### Testing ####### ######################
[docs]def testdata_guifront(defaultdb='testdb1'): import ibeis main_locals = ibeis.main(defaultdb=defaultdb) ibs, back = ut.dict_take(main_locals, ['ibs', 'back']) ibswgt = back.ibswgt # NOQA globals__ = globals() locals__ = locals() def testdata_main_loop(globals_=globals__, locals_=locals__): locals_ = locals_.copy() globals_ = globals_.copy() locals_.update(locals__) globals_.update(globals__) if '--cmd' in sys.argv: guitool.qtapp_loop(qwin=ibswgt, ipy=True) six.exec_(ut.ipython_execstr(), globals_, locals_) elif ut.show_was_requested(): guitool.qtapp_loop(qwin=ibswgt) return ibs, back, ibswgt, testdata_main_loop
[docs]def testfunc(): r""" CommandLine: python -m ibeis.gui.newgui --test-testfunc --show python -m ibeis.gui.newgui --test-testfunc --cmd Example: >>> # DISABLE_DOCTEST >>> from ibeis.gui.newgui import * # NOQA >>> result = testfunc() >>> print(result) """ ibs, back, ibswgt, testdata_main_loop = testdata_guifront() view = ibswgt.views[gh.IMAGE_TABLE] testdata_main_loop(globals(), locals())
if __name__ == '__main__': """ CommandLine: python -m ibeis.gui.newgui python -m ibeis.gui.newgui --allexamples python -m ibeis.gui.newgui --allexamples --noface --nosrc """ import multiprocessing multiprocessing.freeze_support() # for win32 import utool as ut # NOQA ut.doctest_funcs()