def __init__(self, params, actions, *args, **kwargs): super().__init__(*args, **kwargs) self.actions = actions self.params = params # Set the window title self.set_wmclass("Pharmaship", "Pharmaship") self.set_title("Pharmaship") self.set_icon_from_file(utils.get_template("pharmaship_icon.png")) # Set default mode self.mode = "dashboard" # Set default refresh view action (dummy function) self.refresh_view = lambda: None self.builder = Gtk.Builder() self.builder.set_translation_domain("com.devmaretique.pharmaship") self.layout = Gtk.Box(spacing=6, orientation=Gtk.Orientation.VERTICAL) self.add(self.layout) # self.set_border_width(10) # TEMPORARY image = Gtk.Image.new_from_file(utils.get_template("home.png")) self.layout.pack_start(image, True, True, 0) self.build_header_bar()
def build_header_bar(self): # Header bar hb = Gtk.HeaderBar() self.builder.expose_object("header-bar", hb) hb.set_show_close_button(True) # hb.props.title = "Pharmaship" hb.set_title("Pharmaship") self.set_titlebar(hb) self.set_title("Pharmaship") # Menu button builder = Gtk.Builder.new_from_file( utils.get_template("settings_menu.xml")) menu = builder.get_object("app-menu") button = widgets.ButtonWithImage("open-menu-symbolic", btn_class=Gtk.MenuButton) popover = Gtk.Popover.new_from_model(button, menu) button.set_popover(popover) hb.pack_end(button) # Search bar self.searchbar = Gtk.SearchEntry() self.searchbar.set_placeholder_text(_("Search something...")) self.searchbar.connect("activate", self.on_search) self.searchbar.props.width_request = 300 hb.pack_end(self.searchbar) # Mode button builder = Gtk.Builder.new_from_file( utils.get_template("mode_menu.xml")) menu = builder.get_object("app-menu") self.mode_button = Gtk.MenuButton(self.mode) popover = Gtk.Popover.new_from_model(self.mode_button, menu) self.mode_button.set_popover(popover) self.mode_button.props.width_request = 120 self.mode_button.get_style_context().add_class("suggested-action") hb.pack_start(self.mode_button) # Save button button = widgets.ButtonWithImage("document-save-as-symbolic", tooltip=_("Export as PDF"), action="app.save") hb.pack_start(button) self.builder.expose_object("hb-btn-save", button) # Create hb date check button self.create_hb_date_button() self.expiry_date_button_label()
def dialog_delete(self, source, article): builder = Gtk.Builder.new_from_file( utils.get_template("article_delete.glade")) dialog = builder.get_object("dialog") # Set the current values name = builder.get_object("name") name.set_text("{0} ({1}) - quantity: {2}".format( article["name"], article["exp_date"], article["quantity"])) # Delete reason combo box reason_combo = builder.get_object("reason") utils.reason_combo(reason_combo, expired=article["expired"]) # Connect signals builder.connect_signals({ "on-response": (self.response_delete, dialog, article, builder), "on-cancel": (utils.dialog_destroy, dialog), }) dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def dialog_add(self, source, item): builder = Gtk.Builder.new_from_file(utils.get_template("subitem_add.glade")) dialog = builder.get_object("dialog") combobox = builder.get_object("item") self.subitem_combobox(combobox, item) combobox.connect("changed", self.combobox_changed, builder) remaining = builder.get_object("remaining") quantity = builder.get_object("quantity") quantity.connect("changed", self.quantity_changed, remaining) quantity_adjustment = builder.get_object("quantity_adjustment") quantity_adjustment.set_lower(0) remaining_adjustment = builder.get_object("remaining_adjustment") remaining_adjustment.set_lower(0) # Connect signals builder.connect_signals({ "on-response": (self.response_add, dialog, item, builder), "on-cancel": (utils.dialog_destroy, dialog) }) query_count_all() dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def build_kits(self, kits=None): data = parser(self.params, kits) query_count_all() for kit in data: # Create a page child_builder = Gtk.Builder.new_from_file(utils.get_template("first_aid_kit.glade")) # child = child_builder.get_object("main-box") child = child_builder.get_object("child-scrolled") child_builder.connect_signals({ "btn-save-clicked": (self.save_kit, child_builder, kit), "btn-cancel-clicked": (self.cancel, child_builder), "btn-modify-clicked": (self.enable_modify, child_builder) }) name = child_builder.get_object("name") name.set_text(kit["name"]) name.set_sensitive(False) location_combo = child_builder.get_object("location") location_combo.set_sensitive(False) utils.location_combo( combo=location_combo, locations=self.params.locations, active=kit["location_id"] ) btn_save = child_builder.get_object("btn-save") btn_save.hide() self.toggled[kit["id"]] = False self.build_grid(child_builder, kit) self.stack.add_titled(child, "first-aid-kit-{0}".format(kit["id"]), kit["name"]) self.children[kit["id"]] = child_builder
def dialog_use(self, source, article): builder = Gtk.Builder.new_from_file( utils.get_template("article_use.glade")) dialog = builder.get_object("dialog") # Set the current values name = builder.get_object("name") name.set_text("{0} ({1})".format(article["name"], article["exp_date"])) remaining = builder.get_object("remaining") remaining.set_value(article["quantity"]) remaining_adjustment = builder.get_object("remaining_adjustment") remaining_adjustment.set_lower(0) remaining_adjustment.set_upper(article["quantity"]) quantity_adjustment = builder.get_object("quantity_adjustment") quantity_adjustment.set_lower(0) quantity_adjustment.set_upper(article["quantity"]) builder.connect_signals({ "on-response": (self.response_use, dialog, article, builder), "on-cancel": (utils.dialog_destroy, dialog), "quantity-changed": (utils.item_quantity_changed, remaining) }) dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def on_about(self, action, param): builder = Gtk.Builder.new_from_file( utils.get_template("about_dialog.glade")) about_dialog = builder.get_object("about-dialog") about_dialog.set_transient_for(self.window) # Gtk.AboutDialog(transient_for=self.window, modal=True) about_dialog.present()
def dialog_modify(self, source, data): builder = Gtk.Builder.new_from_file(utils.get_template("location_add.glade")) dialog = builder.get_object("dialog") location_combo = builder.get_object("parent") utils.location_combo( location_combo, locations=self.params.locations, active=data["parent"], empty=True, exclude=[data["id"]] ) name = builder.get_object("name") name.set_text(data["sequence"][-1]) btn_modify = builder.get_object("btn_response") btn_modify.set_label(_("Modify this location")) builder.connect_signals({ "on-response": (self.response_modify, data["id"], dialog, builder), "on-cancel": (utils.dialog_destroy, dialog) }) query_count_all() dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def __init__(self, window): self.window = window self.params = window.params self.vessel = self.params.vessel self.builder = Gtk.Builder.new_from_file(utils.get_template("dashboard.glade")) self.warning_date = self.params.today + datetime.timedelta(days=self.params.setting.expire_date_warning_delay) self.data = {}
def success_dialog(self): """Show a Gtk.MessageDialog to inform the DB copy went fine.""" builder = Gtk.Builder.new_from_file(utils.get_template("db_import_dialog.glade")) dialog = builder.get_object("dialog") dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def dialog_modify(self, source, medicine): builder = Gtk.Builder.new_from_file( utils.get_template("medicine_add.glade")) dialog = builder.get_object("dialog") label = builder.get_object("molecule") label.set_text(medicine["molecule"]["name"]) btn_add = builder.get_object("btn_response") btn_add.set_label(_("Modify the medicine")) location_combo = builder.get_object("location") utils.location_combo(combo=location_combo, locations=self.params.locations, active=medicine["location"]["id"]) # Set the current values name = builder.get_object("name") name.set_text(medicine["name"]) quantity = builder.get_object("quantity") quantity.set_value(medicine["quantity"]) # exp_date = builder.get_object("exp_date") exp_date = builder.get_object("exp_date_raw") exp_date = utils.grid_replace(exp_date, widgets.EntryMasked(mask=DATE_MASK)) builder.expose_object("exp_date", exp_date) date_display = medicine["exp_date"].strftime("%Y-%m-%d") exp_date.get_buffer().set_text(date_display, len(date_display)) if medicine["remark"]: remark = builder.get_object("remark") remark.set_text(medicine["remark"]) if medicine["nc_composition"]: nc_composition = builder.get_object("nc_composition") nc_composition.set_text(medicine["nc_composition"]) if medicine["nc_molecule"]: nc_molecule = builder.get_object("nc_molecule") nc_molecule.set_text(medicine["nc_molecule"]) # If nc_molecule or nc_composition, open the expander if medicine["nc_molecule"] or medicine["nc_composition"]: nc_expander = builder.get_object("nc_expander") nc_expander.set_expanded(True) # Connect signals builder.connect_signals({ "on-response": (self.response_modify, dialog, medicine, builder), "on-cancel": (utils.dialog_destroy, dialog) }) dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def __init__(self, window, application): self.window = window self.params = window.params self.application = application self.builder = Gtk.Builder.new_from_file( get_template("allowance_manager.glade")) self.invalid = False
def error_dialog(self, error): """Show a Gtk.MessageDialog to inform about the error.""" builder = Gtk.Builder.new_from_file(utils.get_template("db_export_dialog.glade")) dialog = builder.get_object("dialog") dialog.props.secondary_text = error dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def dialog_add(self, source, equipment): builder = Gtk.Builder.new_from_file( utils.get_template("article_add.glade")) dialog = builder.get_object("dialog") label = builder.get_object("equipment") label.set_text("{0} ({1})".format(equipment["name"], equipment["packaging"])) # Check if equipment has previous locations to input the latest one as # default to ease the input active_location = None equipment_obj = models.Equipment.objects.get(id=equipment["id"]) try: latest_article = equipment_obj.articles.latest("exp_date") except models.Article.DoesNotExist: latest_article = None # except ObjectDoesNotExist: # latest_article = None if latest_article: active_location = latest_article.location.id log.debug("Found last location: %s", active_location) location_combo = builder.get_object("location") utils.location_combo(combo=location_combo, locations=self.params.locations, active=active_location) # By default name = equipment name name = builder.get_object("name") name.set_text(equipment["name"]) # Expiry date input mask workaround exp_date = builder.get_object("exp_date_raw") exp_date = utils.grid_replace(exp_date, widgets.EntryMasked(mask=DATE_MASK)) # exp_date.connect("activate", self.response_add, dialog, equipment, builder) builder.expose_object("exp_date", exp_date) # Connect signals # builder.connect_signals({ # "on_entry_activate": (self.response_add, dialog, equipment, builder) # }) builder.connect_signals({ "on-response": (self.response_add, dialog, equipment, builder), "on-cancel": (utils.dialog_destroy, dialog) }) query_count_all() dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def dialog_modify(self, source, article): builder = Gtk.Builder.new_from_file( utils.get_template("article_add.glade")) dialog = builder.get_object("dialog") label = builder.get_object("equipment") label.set_text(article["equipment"]["name"]) btn_add = builder.get_object("btn_response") btn_add.set_label(_("Modify the article")) location_combo = builder.get_object("location") utils.location_combo(combo=location_combo, locations=self.params.locations, active=article["location"]["id"]) # Set the current values name = builder.get_object("name") name.set_text(article["name"]) quantity = builder.get_object("quantity") quantity.set_value(article["quantity"]) # Expiration date widget custom exp_date = builder.get_object("exp_date_raw") exp_date = utils.grid_replace(exp_date, widgets.EntryMasked(mask=DATE_MASK)) exp_date.connect("activate", self.response_modify, dialog, article, builder) builder.expose_object("exp_date", exp_date) if article["exp_date"]: date_display = article["exp_date"].strftime("%Y-%m-%d") exp_date.get_buffer().set_text(date_display, len(date_display)) if article["remark"]: remark = builder.get_object("remark") remark.set_text(article["remark"]) if article["nc_packaging"]: nc_packaging = builder.get_object("nc_packaging") nc_packaging.set_text(article["nc_packaging"]) nc_expander = builder.get_object("nc_expander") nc_expander.set_expanded(True) # Connect signals builder.connect_signals({ "on-response": (self.response_modify, dialog, article, builder), "on-cancel": (utils.dialog_destroy, dialog), }) dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def gtk_style(self): """Add CSS styles to the application.""" style_provider = Gtk.CssProvider() css = b"" with open(utils.get_template("style.css"), "rb") as fdesc: css = fdesc.read() style_provider.load_from_data(css) Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
def show_detail(self, source, param): builder = Gtk.Builder.new_from_file(utils.get_template("dashboard_detail.glade")) window = builder.get_object("window") window.set_transient_for(self.window) title = "{0} {1}".format(TYPES[param[1]], SECTIONS[param[0]]) window.set_title(title) treeview = builder.get_object("detail-treeview") treeview.set_property("enable-grid-lines", True) # Create headers text_renderer = Gtk.CellRendererText() text_renderer.set_property("wrap_mode", Pango.WrapMode.WORD_CHAR) text_renderer.set_property("wrap_width", 200) # Renderer for quantities, right-aligned, monospace font right_renderer = Gtk.CellRendererText() right_renderer.set_property("family-set", True) right_renderer.set_property("family", "mono") right_renderer.set_property("xalign", 1.0) right_renderer.set_property("xpad", 10) column = Gtk.TreeViewColumn(_("Name"), text_renderer, text=0) column.set_expand(True) treeview.append_column(column) # Format: xx/yy (current qty/required qty) column = Gtk.TreeViewColumn(_("Quantity"), right_renderer, text=1) treeview.append_column(column) if param[1] == "missing": # Missing = required - current quantity column = Gtk.TreeViewColumn(_("Missing"), right_renderer, text=2) treeview.append_column(column) elif param[1] in ["perished", "warning"]: column = Gtk.TreeViewColumn(_("Expiry"), text_renderer, text=2) treeview.append_column(column) elif param[1] == "nc": column = Gtk.TreeViewColumn(_("Non conformity"), text_renderer, text=2) column.set_expand(True) treeview.append_column(column) treeview.set_model( self.create_list_store(section=param[0], type=param[1]) ) builder.connect_signals({ "copy-txt": (self.copy, "txt", param), "copy-csv": (self.copy, "csv", param) }) window.show()
def show_dialog(self): builder = Gtk.Builder.new_from_file(utils.get_template("db_export.glade")) dialog = builder.get_object("dialog") builder.connect_signals({ "on-response": (self.db_export, dialog), "on-cancel": (utils.dialog_destroy, dialog) }) dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def __init__(self, window): self.window = window self.params = window.params self.builder = Gtk.Builder.new_from_file( utils.get_template("sidebar_layout.glade")) self.stack = self.builder.get_object("stack") # For recording the open equipments in the grid self.toggled = {0: False} self.children = {}
def build_full_list(self, data): child_builder = Gtk.Builder.new_from_file( utils.get_template("rescue_bag.glade")) # child = child_builder.get_object("main-box") child = child_builder.get_object("child-scrolled") # Destroy the top grid containing rescue bag edit form top_grid = child_builder.get_object("top-grid") top_grid.destroy() self.build_full_grid(child_builder, data["all"]) self.stack.add_titled(child, "all", _("All Rescue Bags")) self.children[0] = child_builder
def dialog_add(self, source, molecule): builder = Gtk.Builder.new_from_file( utils.get_template("medicine_add.glade")) dialog = builder.get_object("dialog") label = builder.get_object("molecule") label.set_text("{0} ({1} - {2})".format(molecule["name"], molecule["dosage_form"], molecule["composition"])) # Check if molecule has previous locations to input the latest one as # default to ease the input active_location = None molecule_obj = models.Molecule.objects.get(id=molecule["id"]) try: latest_medicine = molecule_obj.medicines.latest("exp_date") except models.Medicine.DoesNotExist: latest_medicine = None if latest_medicine: active_location = latest_medicine.location.id log.debug("Found last location: %s", active_location) location_combo = builder.get_object("location") utils.location_combo(combo=location_combo, locations=self.params.locations, active=active_location) # By default name = molecule name name = builder.get_object("name") name.set_text(molecule["name"]) # Expiry date input mask workaround exp_date = builder.get_object("exp_date_raw") exp_date = utils.grid_replace(exp_date, widgets.EntryMasked(mask=DATE_MASK)) # exp_date.connect("activate", self.response_add, dialog, molecule, builder) builder.expose_object("exp_date", exp_date) # Connect signals builder.connect_signals({ # "on-entry-activate": (self.response_add, dialog, molecule, builder), "on-response": (self.response_add, dialog, molecule, builder), "on-cancel": (utils.dialog_destroy, dialog) }) query_count_all() dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def dialog_delete(self, source, data): builder = Gtk.Builder.new_from_file(utils.get_template("location_delete.glade")) dialog = builder.get_object("dialog") label_string = " > ".join(data["sequence"]) label = builder.get_object("location") label.set_label(label_string) builder.connect_signals({ "on-response": (self.response_delete, data["id"], dialog, builder), "on-cancel": (utils.dialog_destroy, dialog) }) dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def dialog_delete(self, total): # Check the real number of RescueBag instances to delete current = RescueBag.objects.count() count = current - total if count <= 0: log.debug( "Number of RescueBag in database is high than requested.") return builder = Gtk.Builder.new_from_file( get_template("rescue_bag_dialog.glade")) dialog = builder.get_object("dialog") # Set message (showing remaining rescue bags to select for deletion) # Adapt for plural form label = builder.get_object("label") btn = builder.get_object("btn-delete") if count < 2: msg_text = _("Select the rescue bag to delete.") btn.set_label(_("Delete this rescue bag")) else: msg_text = _("Select the {0} rescue bags to delete.") btn.set_label(_("Delete these rescue bags")) label.set_text(msg_text.format(count)) # Create the Treeview self.build_rescue_bag_tree(builder, count) # Connect signals builder.connect_signals({ "on-response": (self.response_delete, dialog, builder, count), "on-cancel": (self.dialog_destroy, dialog), }) query_count_all() dialog.run() dialog.destroy()
def build_bags(self, data, bags): # Get the location_id of all bags to avoid the possibility to select a # bag as a location. exclude_ids = bags.values_list("location_id", flat=True) for bag in bags: # Create a page child_builder = Gtk.Builder.new_from_file( utils.get_template("rescue_bag.glade")) # child = child_builder.get_object("main-box") child = child_builder.get_object("child-scrolled") child_builder.connect_signals({ "btn-save-clicked": (self.save_bag, child_builder, bag), "btn-cancel-clicked": (self.cancel, child_builder), "btn-modify-clicked": (self.enable_modify, child_builder) }) name = child_builder.get_object("name") name.set_text(bag.name) name.set_sensitive(False) location_combo = child_builder.get_object("location") location_combo.set_sensitive(False) utils.location_combo(combo=location_combo, locations=self.params.locations, active=bag.location.parent_id, exclude=exclude_ids) btn_save = child_builder.get_object("btn-save") btn_save.hide() self.toggled[bag.id] = False self.build_grid(child_builder, data, bag) self.stack.add_titled(child, "rescue-bag-{0}".format(bag.id), bag.name) self.children[bag.id] = child_builder
def dialog_modify(self, source, data): item = data[0] perishable = data[1] builder = Gtk.Builder.new_from_file(utils.get_template("subitem_modify.glade")) dialog = builder.get_object("dialog") name = builder.get_object("name") name.set_text(item["name"]) quantity = builder.get_object("quantity") quantity.set_value(item["quantity"]) exp_date = builder.get_object("exp_date_raw") exp_date = utils.grid_replace(exp_date, widgets.EntryMasked(mask=DATE_MASK)) # exp_date.connect("activate", self.response_modify, dialog, item, perishable, builder) builder.expose_object("exp_date", exp_date) date_display = item["exp_date"].strftime("%Y-%m-%d") exp_date.get_buffer().set_text(date_display, len(date_display)) if item["remark"]: remark = builder.get_object("remark") remark.set_text(item["remark"]) if item["nc"]: remark = builder.get_object("nc") remark.set_text(item["nc"]) builder.connect_signals({ "on-response": (self.response_modify, dialog, item, perishable, builder), "on-cancel": (utils.dialog_destroy, dialog) }) dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def dialog_add(self, source): log.debug("Add location") builder = Gtk.Builder.new_from_file(utils.get_template("location_add.glade")) dialog = builder.get_object("dialog") location_combo = builder.get_object("parent") utils.location_combo( location_combo, locations=self.params.locations, empty=True ) builder.connect_signals({ "on-response": (self.response_add, dialog, builder), "on-cancel": (utils.dialog_destroy, dialog) }) query_count_all() dialog.set_transient_for(self.window) dialog.run() dialog.destroy()
def on_search(self, source): search_text = source.get_text().strip() if len(search_text) < 2: return False search_result = search.search(search_text, self.params) # Create a Popover with ListBox main_builder = Gtk.Builder.new_from_file( utils.get_template("search_popover.glade")) popover = main_builder.get_object("popover") popover.set_relative_to(self.searchbar) popover.get_style_context().add_class("popover-search") popover.props.width_request = self.searchbar.props.width_request listbox = main_builder.get_object("listbox") if len(search_result) == 0: row = Gtk.ListBoxRow() label = Gtk.Label(_("No result found. Try again!")) row.add(label) listbox.add(row) listbox.set_selection_mode(0) popover.show_all() scrolled = main_builder.get_object("scrolled") scrolled.set_min_content_height(-1) scrolled.set_max_content_height(-1) return True for item in search_result: builder = Gtk.Builder.new_from_file( utils.get_template("search_listboxrow.glade")) row = Gtk.ListBoxRow() box = builder.get_object("box") row.add(box) listbox.add(row) parent_name = builder.get_object("parent_name") parent_name_text = "<b>{0}</b> ({1})".format( item["parent_name"], item["details"]) parent_name.set_markup(parent_name_text) other_names = builder.get_object("other_names") if item["other_names"]: other_names_text = ", ".join(item["other_names"]) other_names.set_text( _("Other names: {0}").format(other_names_text)) else: other_names.destroy() locations = builder.get_object("locations") if item["locations"]: locations_text = ", ".join(item["locations"]) locations.set_text(_("Locations: {0}").format(locations_text)) else: locations.destroy() quantity_text = "<b>{0}<small>/{1}</small></b>".format( item["quantity"], item["required"]) quantity = builder.get_object("quantity") quantity.set_markup(quantity_text) group = builder.get_object("group") group.set_text(item["group"]) # Type box = builder.get_object("type-box") for item_type in item["type"]: btn = Gtk.LinkButton("", item_type["label"]) # Remove the "pseudo" tooltip showing nothing but existing... btn.set_tooltip_text(None) btn.connect("activate-link", self.search_click, item, item_type["name"]) box.pack_start(btn, True, True, 0) popover.show_all()
def __init__(self, window): self.window = window self.params = window.params self.vessel = self.params.vessel self.builder = Gtk.Builder.new_from_file( utils.get_template("vessel_settings.glade"))