def setup_layout(self): self.model = ResultListModel() image_list_view = QListView() image_list_view.setModel(self.model) image_list_view.setItemDelegate(ResultListItemDelegate()) self.file_path = QLineEdit(self) def add_preview(widget_name): preview = ImageWidget(self) if widget_name: self.__setattr__(widget_name, preview) return preview def add_button(widget_name, caption, trigger): button = QPushButton(caption, self) self.connect(button, SIGNAL('clicked()'), trigger) self.__setattr__(widget_name, button) return button self.status_label = QLabel() button_box = QHBoxLayout() button_box.addWidget(add_button('select_btn', 'Select File', self.select_image)) button_box.addStretch() button_box.addWidget(self.status_label) button_box.addWidget(add_button('reconnect_btn', 'Reconnect', self.asynchronous_login)) button_box.addWidget(add_button('settings_btn', 'Settings', self.show_settings_dialog)) button_box.addWidget(add_button('retrieve_btn', 'Retrieve', self.retrieve_image)) button_box.addWidget(add_button('upload_btn', 'Upload', self.upload_image)) self.lock_buttons() grid_layout = QGridLayout() grid_layout.addWidget(QLabel('Original image:'), 0, 0) grid_layout.addWidget(QLabel('Encrypted image:'), 0, 1) grid_layout.addWidget(add_preview('selected_preview'), 1, 0, 1, 1, Qt.AlignCenter) grid_layout.addWidget(add_preview('encrypt_preview'), 1, 1, 1, 1, Qt.AlignCenter) grid_layout.addWidget(self.file_path, 2, 0, 1, 2) grid_layout.addLayout(button_box, 3, 0, 1, 2) grid_layout.addWidget(image_list_view, 4, 0, 1, 2) self.setLayout(grid_layout)
class SecureRetrievalUI(QDialog, object): DEFAULT_X0_VALUE = np.float64(0.7000000000000001) DEFAULT_R_VALUE = np.float64(3.6000000000000001) DEFAULT_S_VALUE = 255 def __init__(self): super(SecureRetrievalUI, self).__init__() self.setup_misc() self.setup_layout() self.setup_settings_dialog() self.setup_log_dialog() self.connect(self, SIGNAL('results_prepared'), self._results_prepared) self.connect(self, SIGNAL('showCriticalBox'), self.show_critical_box) self.connect(self, SIGNAL('unlock_buttons()'), self.unlock_buttons) self.connect(self, SIGNAL('fetch_done'), self.fetch_done) self.resize(0, 550) self.setMaximumWidth(508) self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint) self.setWindowTitle(u'Secure Image Retrieval Client (powered by 武汉大学对不队)') self.asynchronous_login() def setup_misc(self): self.last_dir_path = '' self.result_path = 'results' self.logged_in = False self.retrieve_block = False self.max_result_count = 10 # self.settings_done() key_group = (self.DEFAULT_X0_VALUE, self.DEFAULT_R_VALUE, self.DEFAULT_S_VALUE) self.core = ClientCore((key_group, key_group, key_group)) def setup_log_dialog(self): self.log_widget = QTextBrowser() handler = LoggerHandler(self.log_widget) handler.setFormatter(ColoredFormatter( fmt='%(asctime)s %(levelname)s %(message)s', colors={'asctime': lambda _: 'blue', 'levelname': lambda lvl: ColoredFormatter.gen_colorscheme()[lvl]}, datefmt='%m/%dT%H:%M:%S' )) self.core.logger.addHandler(handler) self.connect(self.log_widget, SIGNAL('newLog(QString)'), self.new_log) dialog = QDialog(self) dialog.setWindowTitle(u'Log') dialog.resize(400, 200) dialog.move(400, 200) layout = QVBoxLayout(dialog) layout.addWidget(self.log_widget) dialog.setLayout(layout) self.log_dialog = dialog def show_log_dialog(self): if self.log_dialog.isVisible(): self.log_dialog.hide() else: self.log_dialog.show() def settings_done(self): def get_key_group(key_group_widget): return (np.float64(str(key_group_widget[0].text())), np.float64(str(key_group_widget[1].text())), int(str(key_group_widget[2].text()))) keys = map(get_key_group, [self.settings_dialog.key_group_1, self.settings_dialog.key_group_2, self.settings_dialog.key_group_3]) server_addr = str(self.settings_dialog.ip_addr_le.text()) if self.core.server_addr != server_addr: if self.logged_in: self.core.finalize_core() self.lock_buttons() self.logged_in = False self.core = ClientCore(keys, server_addr=server_addr) self.asynchronous_login() self.core.set_keys(keys) self.settings_dialog.hide() def setup_settings_dialog(self): dialog = QDialog(self) dialog.setWindowTitle('Settings') dialog.ip_addr_le = QLineEdit('http://127.0.0.1:5000') def gen_float64_widget(top, bottom, default_value): validator = QDoubleValidator(self) validator.setNotation(QDoubleValidator.StandardNotation) validator.setRange(top, bottom) validator.setDecimals(16) line_edit = QLineEdit('%1.16f' % default_value) line_edit.setValidator(validator) return line_edit def gen_x0_widget(): return gen_float64_widget(-1, 1, self.DEFAULT_X0_VALUE) def gen_r_widget(): return gen_float64_widget(3.57, 4, self.DEFAULT_R_VALUE) def gen_s_widget(): validator = QIntValidator(self) validator.setBottom(0) line_edit = QLineEdit(str(self.DEFAULT_S_VALUE)) line_edit.setMaximumWidth(40) line_edit.setValidator(validator) return line_edit dialog.key_group_1 = [gen_x0_widget(), gen_r_widget(), gen_s_widget()] dialog.key_group_2 = [gen_x0_widget(), gen_r_widget(), gen_s_widget()] dialog.key_group_3 = [gen_x0_widget(), gen_r_widget(), gen_s_widget()] button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.connect(button_box, SIGNAL('accepted()'), self.settings_done) self.connect(button_box, SIGNAL('rejected()'), lambda: dialog.hide()) show_log_button = QPushButton('Show Log') self.connect(show_log_button, SIGNAL('clicked()'), self.show_log_dialog) g_layout = QGridLayout() label = QLabel('Server address') label.setBuddy(dialog.ip_addr_le) g_layout.addWidget(label, 0, 0, 1, 1) g_layout.addWidget(dialog.ip_addr_le, 0, 1, 1, 1) def add_key_group(g_layout, row, x0, r, s): label = QLabel('x<sub>0</sub>') label.setBuddy(x0) g_layout.addWidget(label, row, 0) g_layout.addWidget(x0, row, 1) label = QLabel('r') label.setBuddy(r) g_layout.addWidget(label, row, 2) g_layout.addWidget(r, row, 3) label = QLabel('s') label.setBuddy(s) g_layout.addWidget(label, row, 4) g_layout.addWidget(s, row, 5) _l = QGridLayout() add_key_group(_l, 0, *dialog.key_group_1) add_key_group(_l, 1, *dialog.key_group_2) add_key_group(_l, 2, *dialog.key_group_3) g_layout.addLayout(_l, 1, 0, 1, 2) g_layout.addWidget(show_log_button, 4, 0) g_layout.addWidget(button_box, 4, 1) dialog.setLayout(g_layout) dialog.setMaximumSize(dialog.sizeHint()) self.settings_dialog = dialog def show_settings_dialog(self): if not self.settings_dialog.isVisible(): self.settings_dialog.show() else: self.settings_dialog.hide() def setup_layout(self): self.model = ResultListModel() image_list_view = QListView() image_list_view.setModel(self.model) image_list_view.setItemDelegate(ResultListItemDelegate()) self.file_path = QLineEdit(self) def add_preview(widget_name): preview = ImageWidget(self) if widget_name: self.__setattr__(widget_name, preview) return preview def add_button(widget_name, caption, trigger): button = QPushButton(caption, self) self.connect(button, SIGNAL('clicked()'), trigger) self.__setattr__(widget_name, button) return button self.status_label = QLabel() button_box = QHBoxLayout() button_box.addWidget(add_button('select_btn', 'Select File', self.select_image)) button_box.addStretch() button_box.addWidget(self.status_label) button_box.addWidget(add_button('reconnect_btn', 'Reconnect', self.asynchronous_login)) button_box.addWidget(add_button('settings_btn', 'Settings', self.show_settings_dialog)) button_box.addWidget(add_button('retrieve_btn', 'Retrieve', self.retrieve_image)) button_box.addWidget(add_button('upload_btn', 'Upload', self.upload_image)) self.lock_buttons() grid_layout = QGridLayout() grid_layout.addWidget(QLabel('Original image:'), 0, 0) grid_layout.addWidget(QLabel('Encrypted image:'), 0, 1) grid_layout.addWidget(add_preview('selected_preview'), 1, 0, 1, 1, Qt.AlignCenter) grid_layout.addWidget(add_preview('encrypt_preview'), 1, 1, 1, 1, Qt.AlignCenter) grid_layout.addWidget(self.file_path, 2, 0, 1, 2) grid_layout.addLayout(button_box, 3, 0, 1, 2) grid_layout.addWidget(image_list_view, 4, 0, 1, 2) self.setLayout(grid_layout) def new_log(self, log): self.log_widget.append(log) def asynchronous_login(self): if self.logged_in: return def _t(): try: r = self.core.init_core() if r['status'] == 'ok': self.core.logger.info('connected to server at %s, have fun', self.core.server_addr) self.emit(SIGNAL('unlock_buttons()')) self.logged_in = True else: self.emit(SIGNAL('showCriticalBox'), QString('Initializing'), QString(r['comment'])) except ConnectionError: self.core.logger.critical('cannot connect to server at %s', self.core.server_addr) self.emit(SIGNAL('showCriticalBox'), QString('Initializing'), QString('Seems that there isn\'t any server running on %1.') .arg(self.core.server_addr)) t = threading.Thread(target=_t) t.start() def show_critical_box(self, title, text): self.show_message_box(QMessageBox.critical, title, text) def show_message_box(self, box_type, title, text): box_type(self, title, text, 'OK') def lock_buttons(self): self.retrieve_btn.setEnabled(False) self.upload_btn.setEnabled(False) self.reconnect_btn.setEnabled(True) def unlock_buttons(self): self.retrieve_btn.setEnabled(True) self.upload_btn.setEnabled(True) self.reconnect_btn.setEnabled(False) def select_image(self, fn=''): if not fn: fn = QFileDialog.getOpenFileName(self, 'Open file', self.last_dir_path, 'JPEG files (*.jpg)') if not fn: return self.last_dir_path = os.path.dirname(str(fn)) self.file_path.setText(fn) self.selected_preview.loadImageFromPath(fn) self.buf_encrypted = self.core.save_img_m(self.core.enc_img(str(fn))) self.encrypt_preview.loadImageFromBuffer(self.buf_encrypted) def upload_image(self): if not self.file_path.text(): self.select_image() try: r = self.core.upload_img(self.buf_encrypted) msg = r['status'] if msg == 'ok': self.core.logger.info('file uploaded') else: self.show_message_box(QMessageBox.critical, 'Upload', r['comment']) self.core.logger.critical('file not uploaded due to error') except ConnectionError: self.show_message_box(QMessageBox.critical, 'Upload', 'Server is unavailable.') self.core.logger.critical('server %s is unavailable', self.core.server_addr) finally: self.file_path.setText('') def retrieve_image(self, folder='results'): if self.retrieve_block: self.show_message_box(QMessageBox.warning, 'Retrieve', 'Please wait for this request to be finished.') return if not self.file_path.text(): self.select_image() if not self.file_path.text(): return self.status_label.setText('') count = len(self.model._data) self.model.beginRemoveRows(QModelIndex(), 0, count - 1) while self.model._data: self.model._data.pop(0) self.model.endRemoveRows() def _t(): try: self.retrieve_block = True r = self.core.send_img(self.buf_encrypted, max_count=self.max_result_count) self.emit(SIGNAL('results_prepared'), r, folder) except ConnectionError: self.emit(SIGNAL('showCriticalBox'), QString('Retrieve'), QString('Server is unavailable.')) self.retrieve_block = False self.core.logger.info('server %s is unavailable', self.core.server_addr) prepare_result_thread = threading.Thread(target=_t) prepare_result_thread.start() self.file_path.setText('') def _results_prepared(self, r, folder='results'): n = min(r['result'], self.max_result_count) self.status_label.setText('<font color="blue"><b>' 'fetching...' '</b></font>') self.core.logger.info('results are prepared at server within %s sec, ' 'waiting for fetching', r['time_elapsed']) lock = threading.Lock() result_queue = deque() def _t(i, counter): try: data, dist = self.core.parse_result(None) self.core.logger.info('got result %s, dist = %s', i, dist) if isinstance(dist, basestring): return else: result_queue.append((data, dist, i)) finally: with lock: counter.inc() counter = Counter() start = timeit.default_timer() for i in range(n): threading.Thread(target=_t, args=(i, counter)).start() def _watcher(): while True: if len(result_queue) > 0: data, dist, i = result_queue.pop() dec_img = self.core.dec_img( array=self.core._from_raw_to_grayscale(data) ) buf = self.core.save_img_m(dec_img) fn = self.core.write_result(dec_img, i, folder=folder) self.model.beginInsertRows(QModelIndex(), 0, 0) self.model.append(buf, dist, fn) self.core.logger.info('appending thumbnail %s into list', i) self.model.endInsertRows() if counter >= n and len(result_queue) < 1: break self.model.sort() self.core.logger.info('results sorted by distance') self.retrieve_block = False self.core.logger.info('image retrieval is done within %s sec', '%2.5f' % (timeit.default_timer() - start)) self.emit(SIGNAL('fetch_done')) threading.Thread(target=_watcher).start() def fetch_done(self): self.status_label.setText('<font color="green"><b>' '%s' '</b></font>' % 'done') def closeEvent(self, event): if self.logged_in: t = threading.Thread(target=lambda: self.core.finalize_core()) t.start()