Exemplo n.º 1
0
    def __init__(self, parent):
        super(StoragesFrame, self).__init__(parent)
        
        # create categories data
        self.tree_categories_manager = helper.tree.TreeManager(self.tree_categories)
        self.tree_categories_manager.AddTextColumn("name")
        self.tree_categories_manager.AddTextColumn("description")
        self.tree_categories_manager.DropAccept(DataModelCategory, self.onTreeCategoriesDropCategory)
        self.tree_categories_manager.DropAccept(DataModelStorage, self.onTreeCategoriesDropStorage)
        self.tree_categories_manager.OnSelectionChanged = self.onTreeCategoriesSelChanged

        # storages filters
        self.storages_filter = Filter(self.filters_panel, self.onButtonRemoveFilterClick)

        # create storage list
        self.tree_storages_manager = TreeManagerStorages(self.tree_storages)
        self.tree_storages_manager.AddIntegerColumn("id")
        self.tree_storages_manager.AddTextColumn("name")
        self.tree_storages_manager.AddTextColumn("description")
        self.tree_storages_manager.AddIntegerColumn("comment")
        self.tree_storages_manager.OnSelectionChanged = self.onTreeStoragesSelChanged

        # create storage part list
        self.tree_storage_parts_manager = helper.tree.TreeManager(self.tree_storage_parts)
        self.tree_storage_parts_manager.AddIntegerColumn("id")
        self.tree_storage_parts_manager.AddTextColumn("name")
        self.tree_storage_parts_manager.AddIntegerColumn("quantity")
        self.tree_storage_parts_manager.AddTextColumn("description")
        self.tree_storage_parts_manager.OnSelectionChanged = self.onTreeStoragePartsSelChanged

        # initial edit state
        self.show_storage(None)
        self.edit_state = None

        self.loaded = False ;
Exemplo n.º 2
0
    def __init__(self, parent): 
        super(PartsFrame, self).__init__(parent)
        
        # create categories list
        self.tree_categories_manager = helper.tree.TreeManager(self.tree_categories)
        self.tree_categories_manager.AddTextColumn("name")
        self.tree_categories_manager.AddTextColumn("description")
        self.tree_categories_manager.DropAccept(DataModelCategory, self.onTreeCategoriesDropCategory)
        self.tree_categories_manager.DropAccept(DataModelPart, self.onTreeCategoriesDropPart)
        self.tree_categories_manager.OnSelectionChanged = self.onTreeCategoriesSelChanged
        # parts filters
        self.parts_filter = Filter(self.filters_panel, self.onButtonRemoveFilterClick)
        
        # create parts list
        self.tree_parts_manager = TreeManagerParts(self.tree_parts)
        self.tree_parts_manager.AddIntegerColumn("id")
        self.tree_parts_manager.AddTextColumn("name")
        self.tree_parts_manager.AddTextColumn("description")
        self.tree_parts_manager.AddIntegerColumn("comment")
        self.tree_parts_manager.OnSelectionChanged = self.onTreePartsSelChanged
        self.tree_parts_manager.DropAccept(DataModelPart, self.onTreePartsDropPart)
        
        # 
        # create edit part panel
        self.panel_edit_part = EditPartFrame(self.part_splitter)
        self.part_splitter.SplitHorizontally(self.part_splitter.Window1, self.panel_edit_part, 400)
        self.panel_edit_part.Bind( EVT_EDIT_PART_APPLY_EVENT, self.onEditPartApply )
        self.panel_edit_part.Bind( EVT_EDIT_PART_CANCEL_EVENT, self.onEditPartCancel )

        # initial edit state
        self.show_part(None)
        self.edit_state = None
        
        self.load()
Exemplo n.º 3
0
    def __init__(self, parent): 
        super(PartsFrame, self).__init__(parent)
        
        # create categories list
        self.tree_categories_manager = helper.tree.TreeManager(self.tree_categories, context_menu=self.menu_category)
        self.tree_categories_manager.AddTextColumn("name")
        self.tree_categories_manager.AddTextColumn("description")
        self.tree_categories_manager.DropAccept(DataModelCategory, self.onTreeCategoriesDropCategory)
        self.tree_categories_manager.DropAccept(DataModelPart, self.onTreeCategoriesDropPart)
        self.tree_categories_manager.OnSelectionChanged = self.onTreeCategoriesSelChanged
        self.tree_categories_manager.OnItemBeforeContextMenu = self.onTreeCategoriesBeforeContextMenu

        # parts filters
        self.parts_filter = Filter(self.filters_panel, self.onButtonRemoveFilterClick)
        
        # create parts list
        self.tree_parts_manager = TreeManagerParts(self.tree_parts, context_menu=self.menu_part)
        self.tree_parts_manager.AddIntegerColumn("id")
        self.tree_parts_manager.AddTextColumn("name")
        self.tree_parts_manager.AddTextColumn("description")
        self.tree_parts_manager.AddIntegerColumn("comment")
        self.tree_parts_manager.AddTextColumn("symbol")
        self.tree_parts_manager.AddTextColumn("footprint")
        self.tree_parts_manager.OnSelectionChanged = self.onTreePartsSelChanged
        self.tree_parts_manager.OnColumnHeaderRightClick = self.onTreePartsColumnHeaderRightClick
        self.tree_parts_manager.DropAccept(DataModelPart, self.onTreePartsDropPart)
        self.tree_parts_manager.OnItemBeforeContextMenu = self.onTreePartsBeforeContextMenu
        
        # 
        # create edit part panel
        self.panel_edit_part = EditPartFrame(self.part_splitter)
        self.part_splitter.SplitHorizontally(self.part_splitter.Window1, self.panel_edit_part, 400)
        self.panel_edit_part.Bind( EVT_EDIT_PART_APPLY_EVENT, self.onEditPartApply )
        self.panel_edit_part.Bind( EVT_EDIT_PART_CANCEL_EVENT, self.onEditPartCancel )

        self.toolbar_part.ToggleTool(self.toggle_part_path.GetId(), True)

        # initial edit state
        self.show_part(None)
        self.edit_state = None
        self.show_categories = True
        
        self.load()
Exemplo n.º 4
0
    def __init__(self, parent):
        super(FootprintsFrame, self).__init__(parent)

        # create categories data
        self.tree_categories_manager = helper.tree.TreeManager(
            self.tree_categories)
        self.tree_categories_manager.AddTextColumn("name")
        self.tree_categories_manager.AddTextColumn("description")
        self.tree_categories_manager.DropAccept(
            DataModelCategory, self.onTreeCategoriesDropCategory)
        self.tree_categories_manager.DropAccept(
            DataModelFootprint, self.onTreeCategoriesDropFootprint)
        self.tree_categories_manager.OnSelectionChanged = self.onTreeCategoriesSelChanged

        # footprints filters
        self.footprints_filter = Filter(self.filters_panel,
                                        self.onButtonRemoveFilterClick)

        # create footprint list
        self.tree_footprints_manager = TreeManagerFootprints(
            self.tree_footprints)
        self.tree_footprints_manager.AddIntegerColumn("id")
        self.tree_footprints_manager.AddTextColumn("name")
        self.tree_footprints_manager.AddTextColumn("description")
        self.tree_footprints_manager.AddIntegerColumn("comment")
        self.tree_footprints_manager.OnSelectionChanged = self.onTreeFootprintsSelChanged

        # create edit footprint panel
        self.panel_edit_footprint = EditFootprintFrame(self.footprint_splitter)
        self.footprint_splitter.SplitHorizontally(
            self.footprint_splitter.Window1, self.panel_edit_footprint, 400)
        self.panel_edit_footprint.Bind(EVT_EDIT_FOOTPRINT_APPLY_EVENT,
                                       self.onEditFootprintApply)
        self.panel_edit_footprint.Bind(EVT_EDIT_FOOTPRINT_CANCEL_EVENT,
                                       self.onEditFootprintCancel)

        # initial edit state
        self.show_footprint(None)
        self.edit_state = None

        self.load()
Exemplo n.º 5
0
class FootprintsFrame(PanelFootprints):
    def __init__(self, parent):
        super(FootprintsFrame, self).__init__(parent)

        # create categories data
        self.tree_categories_manager = helper.tree.TreeManager(
            self.tree_categories)
        self.tree_categories_manager.AddTextColumn("name")
        self.tree_categories_manager.AddTextColumn("description")
        self.tree_categories_manager.DropAccept(
            DataModelCategory, self.onTreeCategoriesDropCategory)
        self.tree_categories_manager.DropAccept(
            DataModelFootprint, self.onTreeCategoriesDropFootprint)
        self.tree_categories_manager.OnSelectionChanged = self.onTreeCategoriesSelChanged

        # footprints filters
        self.footprints_filter = Filter(self.filters_panel,
                                        self.onButtonRemoveFilterClick)

        # create footprint list
        self.tree_footprints_manager = TreeManagerFootprints(
            self.tree_footprints)
        self.tree_footprints_manager.AddIntegerColumn("id")
        self.tree_footprints_manager.AddTextColumn("name")
        self.tree_footprints_manager.AddTextColumn("description")
        self.tree_footprints_manager.AddIntegerColumn("comment")
        self.tree_footprints_manager.OnSelectionChanged = self.onTreeFootprintsSelChanged

        # create edit footprint panel
        self.panel_edit_footprint = EditFootprintFrame(self.footprint_splitter)
        self.footprint_splitter.SplitHorizontally(
            self.footprint_splitter.Window1, self.panel_edit_footprint, 400)
        self.panel_edit_footprint.Bind(EVT_EDIT_FOOTPRINT_APPLY_EVENT,
                                       self.onEditFootprintApply)
        self.panel_edit_footprint.Bind(EVT_EDIT_FOOTPRINT_CANCEL_EVENT,
                                       self.onEditFootprintCancel)

        # initial edit state
        self.show_footprint(None)
        self.edit_state = None

        self.load()

    def loadCategories(self):
        # clear all
        self.tree_categories_manager.ClearItems()

        # load categories
        categories = rest.api.find_footprints_categories()

        # load tree
        to_add = []
        id_category_map = {}
        for category in categories:
            to_add.append(category)
        while len(to_add) > 0:
            category = to_add[0]
            id_category_map[category.id] = DataModelCategory(category)
            to_add.pop(0)

            # add to model
            if category.parent:
                self.tree_categories_manager.AppendItem(
                    id_category_map[category.parent.id],
                    id_category_map[category.id])
            else:
                self.tree_categories_manager.AppendItem(
                    None, id_category_map[category.id])

            # load childs
            if category.childs:
                for child in category.childs:
                    to_add.append(child)

    def loadFootprints(self):
        # clear all
        self.tree_footprints_manager.ClearItems()

        # load footprints
        footprints = rest.api.find_footprints(
            **self.footprints_filter.query_filter())

        # load categories
        categories = {}
        for footprint in footprints:
            if footprint.category:
                category_name = footprint.category.path
            else:
                category_name = "/"

            if categories.has_key(category_name) == False:
                categories[category_name] = DataModelCategoryPath(
                    footprint.category)
                self.tree_footprints_manager.AppendItem(
                    None, categories[category_name])
            self.tree_footprints_manager.AppendItem(
                categories[category_name], DataModelFootprint(footprint))

        for category in categories:
            self.tree_footprints_manager.Expand(categories[category])

    # Virtual event handlers, overide them in your derived class
    def load(self):
        try:
            self.loadCategories()
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

        try:
            self.loadFootprints()
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def show_footprint(self, footprint):
        # disable editing
        self.panel_edit_footprint.enable(False)
        # enable evrything else
        self.panel_category.Enabled = True
        self.panel_footprints.Enabled = True
        # set part
        self.panel_edit_footprint.SetFootprint(footprint)

    def edit_footprint(self, footprint):
        self.show_footprint(footprint)
        # enable editing
        self.panel_edit_footprint.enable(True)
        # disable evrything else
        self.panel_category.Enabled = False
        self.panel_footprints.Enabled = False

    def new_footprint(self):
        footprint = rest.model.FootprintNew()

        # set category
        item = self.tree_categories.GetSelection()
        if item.IsOk():
            category = self.tree_categories_manager.ItemToObject(item)
            if category.category:
                footprint.category = category.category

        self.edit_footprint(footprint)

    def onButtonRefreshCategoriesClick(self, event):
        self.loadCategories()

    def onButtonAddCategoryClick(self, event):
        category = EditCategoryFrame(self).addCategory(
            rest.model.FootprintCategoryNew)
        if category:
            try:
                # retrieve parent item from selection
                parentitem = self.tree_categories.GetSelection()
                parentobj = None
                category.parent = None
                if parentitem:
                    parentobj = self.tree_categories_manager.ItemToObject(
                        parentitem)
                    category.parent = parentobj.category

                # create category on server
                category = rest.api.add_footprints_category(category)
                # create category on treeview
                newitem = self.tree_categories_manager.AppendItem(
                    parentobj, DataModelCategory(category))
                # add category to item element
                self.tree_categories_manager.SelectItem(newitem)
                self.onTreeCategoriesSelChanged(None)
            except Exception as e:
                wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonEditCategoryClick(self, event):
        sel = self.tree_categories.GetSelection()
        categoryobj = self.tree_categories_manager.ItemToObject(sel)
        if categoryobj is None:
            return
        category = EditCategoryFrame(self).editCategory(categoryobj.category)
        if not category is None:
            try:
                categoryobj.category = rest.api.update_footprints_category(
                    categoryobj.category.id, category)
                self.tree_categories_manager.UpdateItem(categoryobj)
                self.onTreeCategoriesSelChanged(None)
            except Exception as e:
                wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonRemoveCategoryClick(self, event):
        sel = self.tree_categories.GetSelection()
        categoryobj = self.tree_categories_manager.ItemToObject(sel)
        if categoryobj is None:
            return
        try:
            res = wx.MessageDialog(
                self, "Remove category '" + categoryobj.category.name + "'",
                "Remove?", wx.OK | wx.CANCEL).ShowModal()
            if res == wx.ID_OK:
                rest.api.delete_footprints_category(categoryobj.category.id)
                self.tree_categories_manager.DeleteItem(
                    categoryobj.parent, categoryobj)
            else:
                return
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonRemoveFilterClick(self, event):
        button = event.GetEventObject()
        self.footprints_filter.remove(button.GetName())
        self.tree_categories.UnselectAll()
        self.loadFootprints()

    def onTreeCategoriesSelChanged(self, event):
        item = self.tree_categories.GetSelection()
        category = None
        if item.IsOk():
            category = self.tree_categories_manager.ItemToObject(item)
        # set category filter
        self.footprints_filter.remove('category')
        if category:
            self.footprints_filter.add('category', category.category.id,
                                       category.category.name)
        # apply new filter and reload
        self.loadFootprints()

    def onTreeCategoriesDropCategory(self, x, y, data):
        dest_categoryitem, _ = self.tree_categories.HitTest((x, y))
        try:
            source_category_id = data['id']
            source_category = rest.api.find_footprints_category(
                source_category_id)
            source_categoryitem = helper.tree.TreeManager.drag_item
            source_categoryobj = self.tree_categories_manager.ItemToObject(
                source_categoryitem)

            dest_category = None
            dest_categoryobj = None
            if dest_categoryitem.IsOk():
                dest_categoryobj = self.tree_categories_manager.ItemToObject(
                    dest_categoryitem)
                dest_category = dest_categoryobj.category
                if source_category_id == dest_category.id:
                    return wx.DragError
                source_category.parent = rest.model.FootprintCategoryRef(
                    id=dest_category.id)
            else:
                # set if as root category
                source_category.parent = None

            # update on server
            category = rest.api.update_footprints_category(
                source_category.id, source_category)

            # update tree model
            if source_categoryobj:
                self.tree_categories_manager.MoveItem(
                    source_categoryobj.parent, dest_categoryobj,
                    source_categoryobj)
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

        return wx.DragMove

    def onTreeCategoriesDropFootprint(self, x, y, data):
        dest_categoryitem, _ = self.tree_categories.HitTest((x, y))

        try:
            source_footprint_id = data['id']
            source_footprint = rest.api.find_footprint(source_footprint_id)

            dest_category = None
            dest_categoryobj = None
            if dest_categoryitem.IsOk():
                dest_categoryobj = self.tree_categories_manager.ItemToObject(
                    dest_categoryitem)
                dest_category = dest_categoryobj.category
                source_footprint.category = rest.model.FootprintCategoryRef(
                    id=dest_category.id)
            else:
                # set if as root category
                source_footprint.category = None

            # update on server
            footprint = rest.api.update_footprint(source_footprint.id,
                                                  source_footprint)

            # update tree model
            self.tree_footprints_manager.DeleteFootprint(source_footprint)
            self.tree_footprints_manager.AppendFootprint(footprint)
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)
        return wx.DragMove

    def onTreeFootprintsSelChanged(self, event):
        item = self.tree_footprints.GetSelection()
        footprint = None
        if not item.IsOk():
            return

        obj = self.tree_footprints_manager.ItemToObject(item)
        if isinstance(obj, DataModelFootprint):
            footprint = obj.footprint
        self.show_footprint(footprint)

    def onEditFootprintApply(self, event):
        footprint = event.data
        try:
            if self.edit_state == 'edit':
                # update part on server
                footprint = rest.api.update_footprint(footprint.id, footprint)
                self.tree_footprints_manager.UpdateFootprint(footprint)
            elif self.edit_state == 'add':
                footprint = rest.api.add_footprint(footprint)
                self.tree_footprints_manager.AppendFootprint(footprint)
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)
            return
        self.edit_state = None
        self.show_footprint(footprint)

    def onEditFootprintCancel(self, event):
        footprint = None
        item = self.tree_footprints.GetSelection()
        if item.IsOk():
            footprintobj = self.tree_footprints_manager.ItemToObject(item)
            footprint = footprintobj.footprint
        self.edit_state = None
        self.show_footprint(footprint)

    def onButtonAddFootprintClick(self, event):
        self.edit_state = 'add'
        self.new_footprint()

    def onButtonEditFootprintClick(self, event):
        item = self.tree_footprints.GetSelection()
        if not item.IsOk():
            return
        obj = self.tree_footprints_manager.ItemToObject(item)
        if isinstance(obj, DataModelCategoryPath):
            return
        self.edit_state = 'edit'
        self.edit_footprint(obj.footprint)
        #
    def onButtonRemoveFootprintClick(self, event):
        item = self.tree_footprints.GetSelection()
        if not item.IsOk():
            return
        obj = self.tree_footprints_manager.ItemToObject(item)
        if isinstance(obj, DataModelCategoryPath):
            return
        footprint = obj.footprint
        res = wx.MessageDialog(self,
                               "Remove footprint '" + footprint.name + "'",
                               "Remove?", wx.OK | wx.CANCEL).ShowModal()
        if res == wx.ID_OK:
            # remove part
            rest.api.delete_footprint(footprint.id)
            self.tree_footprints_manager.DeleteFootprint(footprint)
        else:
            return
        self.show_footprint(None)

    def onButtonRefreshFootprintsClick(self, event):
        self.loadFootprints()

    def onSearchFootprintsTextEnter(self, event):
        # set search filter
        self.footprints_filter.remove('search')
        if self.search_footprints.Value != '':
            self.footprints_filter.add('search', self.search_footprints.Value)
        # apply new filter and reload
        self.loadFootprints()

    def onSearchFootprintsButton(self, event):
        return self.onSearchFootprintsTextEnter(event)
Exemplo n.º 6
0
class StoragesFrame(PanelStorages): 
    def __init__(self, parent):
        super(StoragesFrame, self).__init__(parent)
        
        # create categories data
        self.tree_categories_manager = helper.tree.TreeManager(self.tree_categories)
        self.tree_categories_manager.AddTextColumn("name")
        self.tree_categories_manager.AddTextColumn("description")
        self.tree_categories_manager.DropAccept(DataModelCategory, self.onTreeCategoriesDropCategory)
        self.tree_categories_manager.DropAccept(DataModelStorage, self.onTreeCategoriesDropStorage)
        self.tree_categories_manager.OnSelectionChanged = self.onTreeCategoriesSelChanged

        # storages filters
        self.storages_filter = Filter(self.filters_panel, self.onButtonRemoveFilterClick)

        # create storage list
        self.tree_storages_manager = TreeManagerStorages(self.tree_storages)
        self.tree_storages_manager.AddIntegerColumn("id")
        self.tree_storages_manager.AddTextColumn("name")
        self.tree_storages_manager.AddTextColumn("description")
        self.tree_storages_manager.AddIntegerColumn("comment")
        self.tree_storages_manager.OnSelectionChanged = self.onTreeStoragesSelChanged

        # create storage part list
        self.tree_storage_parts_manager = helper.tree.TreeManager(self.tree_storage_parts)
        self.tree_storage_parts_manager.AddIntegerColumn("id")
        self.tree_storage_parts_manager.AddTextColumn("name")
        self.tree_storage_parts_manager.AddIntegerColumn("quantity")
        self.tree_storage_parts_manager.AddTextColumn("description")
        self.tree_storage_parts_manager.OnSelectionChanged = self.onTreeStoragePartsSelChanged

        # initial edit state
        self.show_storage(None)
        self.edit_state = None

        self.loaded = False ;
        
    def activate(self):
        if self.loaded==False:
            self.load()
        self.loaded = True
        
    def loadCategories(self):
        try:
            check_backend()
        except Exception as e:
            print_stack()
            self.GetParent().GetParent().error_message(format(e))
            return

        # clear all
        self.tree_categories_manager.ClearItems()
        
        # load categories
        categories = rest.api.find_storages_categories()

        # load tree
        to_add = []
        id_category_map = {}
        for category in categories:
            to_add.append(category)
        while len(to_add)>0:
            category = to_add[0]
            id_category_map[category.id] = DataModelCategory(category)
            to_add.pop(0)
            
            # add to symbol
            if category.parent:
                self.tree_categories_manager.AppendItem(id_category_map[category.parent.id], id_category_map[category.id])
            else:
                self.tree_categories_manager.AppendItem(None, id_category_map[category.id])
            
            # load childs
            if category.childs:
                for child in category.childs:
                    to_add.append(child)

    def loadStorages(self):
        try:
            check_backend()
        except Exception as e:
            print_stack()
            self.GetParent().GetParent().error_message(format(e))
            return

        # clear all
        self.tree_storages_manager.ClearItems()
        
        # load storages
        storages = rest.api.find_storages(**self.storages_filter.query_filter())

        # load categories
        categories = {}
        for storage in storages:
            if storage.category:
                category_name = storage.category.path
            else:
                category_name = "/"

            if category_name not in categories:
                categories[category_name] = DataModelCategoryPath(storage.category)
                self.tree_storages_manager.AppendItem(None, categories[category_name])
            self.tree_storages_manager.AppendItem(categories[category_name], DataModelStorage(storage))
        
        for category in categories:
            self.tree_storages_manager.Expand(categories[category])

    # Virtual event handlers, overide them in your derived class
    def load(self):
        try:
            check_backend()
        except Exception as e:
            print_stack()
            self.GetParent().GetParent().error_message(format(e))
            return

        try:
            self.loadCategories()
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

        try:
            self.loadStorages()
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def show_storage(self, storage):
        # enable evrything else
        self.panel_category.Enabled = True
        self.panel_storages.Enabled = True

        self.load_storage_parts(storage)
        
    def load_storage_parts(self, storage):
        if storage is None:
            return 
        parts = rest.api.find_parts(storage=storage.id, with_storages=True)
        
        self.tree_storage_parts_manager.ClearItems()
        for part in parts:
            if part.storages:
                for part_storage in part.storages:
                    if part_storage.id==storage.id:
                        storage_partobj = DataModelStoragePart(part, part_storage.quantity)
                        self.tree_storage_parts_manager.AppendItem(None, storage_partobj)
    
    def onButtonRefreshCategoriesClick( self, event ):
        self.loadCategories()

    def onButtonAddCategoryClick( self, event ):
        category = EditCategoryFrame(self).addCategory(rest.model.StorageCategoryNew)
        if category:
            try:
                # retrieve parent item from selection
                parentitem = self.tree_categories.GetSelection()
                parentobj = None
                category.parent = None
                if parentitem:
                    parentobj = self.tree_categories_manager.ItemToObject(parentitem)
                    category.parent = parentobj.category
                    
                # create category on server
                category = rest.api.add_storages_category(category)
                # create category on treeview
                newitem = self.tree_categories_manager.AppendItem(parentobj, DataModelCategory(category)) 
                # add category to item element
                self.tree_categories_manager.SelectItem(newitem)
                self.onTreeCategoriesSelChanged(None)
            except Exception as e:
                print_stack()
                wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonEditCategoryClick( self, event ):
        sel = self.tree_categories.GetSelection()
        categoryobj = self.tree_categories_manager.ItemToObject(sel)
        if categoryobj is None:
            return
        category = EditCategoryFrame(self).editCategory(categoryobj.category)
        if not category is None:
            try:
                categoryobj.category = rest.api.update_storages_category(categoryobj.category.id, category)
                self.tree_categories_manager.UpdateItem(categoryobj)
                self.onTreeCategoriesSelChanged(None)
            except Exception as e:
                print_stack()
                wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonRemoveCategoryClick( self, event ):
        sel = self.tree_categories.GetSelection()
        categoryobj = self.tree_categories_manager.ItemToObject(sel)
        if categoryobj is None:
            return
        try:
            res = wx.MessageDialog(self, "Remove category '"+categoryobj.category.name+"'", "Remove?", wx.OK|wx.CANCEL).ShowModal()
            if res==wx.ID_OK:
                rest.api.delete_storages_category(categoryobj.category.id)
                self.tree_categories_manager.DeleteItem(categoryobj.parent, categoryobj)
            else:
                return
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonRemoveFilterClick( self, event ):
        button = event.GetEventObject()
        self.storages_filter.remove(button.GetName())
        self.tree_categories.UnselectAll()
        self.loadStorages()

    def onTreeCategoriesSelChanged( self, event ):
        item = self.tree_categories.GetSelection()
        category = None
        if item.IsOk():
            category = self.tree_categories_manager.ItemToObject(item)
        # set category filter
        self.storages_filter.remove('category')
        if category:
            self.storages_filter.add('category', category.category.id, category.category.name)
        # apply new filter and reload
        self.loadStorages()

    def onTreeCategoriesDropCategory(self, x, y, data):
        dest_categoryitem, _ = self.tree_categories.HitTest((x, y))
        try:
            source_category_id = data['id']
            source_category = rest.api.find_storages_category(source_category_id)
            source_categoryitem = helper.tree.TreeManager.drag_item
            source_categoryobj = self.tree_categories_manager.ItemToObject(source_categoryitem)
    
            dest_category = None
            dest_categoryobj = None
            if dest_categoryitem.IsOk():
                dest_categoryobj = self.tree_categories_manager.ItemToObject(dest_categoryitem)
                dest_category = dest_categoryobj.category
                if source_category_id==dest_category.id:
                    return wx.DragError
                source_category.parent = rest.model.StorageCategoryRef(id=dest_category.id)
            else:
                # set if as root category
                source_category.parent = None
            
            # update on server
            category = rest.api.update_storages_category(source_category.id, source_category)

            # update tree symbol
            if source_categoryobj:
                self.tree_categories_manager.MoveItem(source_categoryobj.parent, dest_categoryobj, source_categoryobj)
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

        return wx.DragMove

    def onTreeCategoriesDropStorage(self, x, y, data):
        dest_categoryitem, _ = self.tree_categories.HitTest((x, y))

        try:
            source_storage_id = data['id']
            source_storage = rest.api.find_storage(source_storage_id)

            dest_category = None
            dest_categoryobj = None
            if dest_categoryitem.IsOk():
                dest_categoryobj = self.tree_categories_manager.ItemToObject(dest_categoryitem)
                dest_category = dest_categoryobj.category
                source_storage.category = rest.model.StorageCategoryRef(id=dest_category.id)
            else:
                # set if as root category
                source_storage.category = None
            
            # update on server
            storage = rest.api.update_storage(source_storage.id, source_storage)
            
            # update tree symbol
            self.tree_storages_manager.DeleteStorage(source_storage)
            self.tree_storages_manager.AppendStorage(storage)
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)
        return wx.DragMove

    def onTreeStoragesSelChanged( self, event ):
        item = self.tree_storages.GetSelection()
        storage = None
        if not item.IsOk():
            return
        
        obj = self.tree_storages_manager.ItemToObject(item)
        if isinstance(obj, DataModelStorage):
            storage = obj.storage
        self.show_storage(storage)

    def onEditStorageApply( self, event ):
        storage = event.data
        try:
            if self.edit_state=='edit':
                # update part on server
                storage = rest.api.update_storage(storage.id, storage)
                self.tree_storages_manager.UpdateStorage(storage)
            elif self.edit_state=='add':
                storage = rest.api.add_storage(storage)
                self.tree_storages_manager.AppendStorage(storage)
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)
            return
        self.edit_state = None
        self.show_storage(storage)
     
    def onEditStorageCancel( self, event ):
        storage = None
        item = self.tree_storages.GetSelection()
        if item.IsOk():
            storageobj = self.tree_storages_manager.ItemToObject(item)
            storage = storageobj.storage
        self.edit_state = None
        self.show_storage(storage)

    def onButtonAddStorageClick( self, event ):
        storage = EditStorageFrame(self).addStorage(rest.model.StorageNew)
        if storage:
            try:
                # retrieve parent item from selection
                categoryitem = self.tree_categories.GetSelection()
                categoryobj = None
                storage.category = None
                if categoryitem:
                    categoryobj = self.tree_categories_manager.ItemToObject(categoryitem)
                    storage.category = categoryobj.category
                    
                # create category on server
                storage = rest.api.add_storage(storage)
                # create category on treeview
                newitem = self.tree_storages_manager.AppendItem(None, DataModelStorage(storage)) 
                # add category to item element
                self.tree_storages_manager.SelectItem(newitem)
                self.onTreeStoragesSelChanged(None)
            except Exception as e:
                print_stack()
                wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)
        
    def onButtonEditStorageClick( self, event ):
        sel = self.tree_storages.GetSelection()
        if sel.IsOk()==False:
            return
        storageobj = self.tree_storages_manager.ItemToObject(sel)
        if storageobj is None:
            return
        storage = EditStorageFrame(self).editStorage(storageobj.storage)
        if not storage is None:
            try:
                storageobj.storage = rest.api.update_storage(storageobj.storage.id, storage)
                self.tree_storages_manager.UpdateItem(storageobj)
                self.onTreeStoragesSelChanged(None)
            except Exception as e:
                print_stack()
                wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)
        # 
    def onButtonRemoveStorageClick( self, event ):
        sel = self.tree_storages.GetSelection()
        if sel.IsOk()==False:
            return
        storageobj = self.tree_storages_manager.ItemToObject(sel)
        if storageobj is None:
            return
        try:
            res = wx.MessageDialog(self, "Remove storage '"+storageobj.storage.name+"'", "Remove?", wx.OK|wx.CANCEL).ShowModal()
            if res==wx.ID_OK:
                rest.api.delete_storage(storageobj.storage.id)
                self.tree_storages_manager.DeleteItem(storageobj.parent, storageobj)
                self.onTreeStoragesSelChanged(None)
            else:
                return
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonRefreshStoragesClick( self, event ):
        self.loadStorages()

    def onSearchStoragesTextEnter( self, event ):
        # set search filter
        self.storages_filter.remove('search')
        if self.search_storages.Value!='':
            self.storages_filter.add('search', self.search_storages.Value)
        # apply new filter and reload
        self.loadStorages()

    def onButtonAddStoragePartClick( self, event ):
        item = self.tree_storages.GetSelection()
        if item.IsOk()==False:
            return
        obj = self.tree_storages_manager.ItemToObject(item)
        if isinstance(obj, DataModelStorage)==False:
            return
        
        dropdown = DropdownDialog(self.button_add_storage_part, SelectPartFrame, "")
        dropdown.panel.Bind( EVT_SELECT_PART_OK_EVENT, self.onSelectPartCallback )
        dropdown.Dropdown()
    
    def onButtonRemoveStoragePartClick( self, event ):
        event.Skip()

    def onSearchStoragesButton(self, event):
        return self.onSearchStoragesTextEnter(event)

    def onTreeStoragePartsSelChanged( self, event ):
        pass
    
    def onButtonAddStorageItemClick( self, event ):
        item = self.tree_storages.GetSelection()
        if item.IsOk()==False:
            return
        storageobj = self.tree_storages_manager.ItemToObject(item)
        if isinstance(storageobj, DataModelStorage)==False:
            return
        
        sel = self.tree_storage_parts.GetSelection()
        if sel.IsOk()==False:
            return
        partobj = self.tree_storage_parts_manager.ItemToObject(sel)
        if partobj is None:
            return
        
        if self.spin_num_parts.Value==0:
            return
        
        try:
            res = wx.MessageDialog(self, "Add %d items of %s to storage?"%(self.spin_num_parts.Value, partobj.part.name), "Add?", wx.OK|wx.CANCEL).ShowModal()
            if res==wx.ID_OK:
                part = rest.api.find_part(partobj.part.id, with_storages=True)
                for part_storage in part.storages:
                    if part_storage.id==storageobj.storage.id:
                        part_storage.quantity = part_storage.quantity+self.spin_num_parts.Value
                        break
            
                partobj.part = rest.api.update_part(part.id, part)
                partobj.quantity = part_storage.quantity
                self.tree_storage_parts_manager.UpdateItem(partobj)
            else:
                return
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonRemoveStorageItemClick( self, event ):
        item = self.tree_storages.GetSelection()
        if item.IsOk()==False:
            return
        storageobj = self.tree_storages_manager.ItemToObject(item)
        if isinstance(storageobj, DataModelStorage)==False:
            return
        
        sel = self.tree_storage_parts.GetSelection()
        if sel.IsOk()==False:
            return
        partobj = self.tree_storage_parts_manager.ItemToObject(sel)
        if partobj is None:
            return
        
        if self.spin_num_parts.Value==0:
            return
        
        try:
            res = wx.MessageDialog(self, "Remove %d items of %s to storage?"%(self.spin_num_parts.Value, partobj.part.name), "Remove?", wx.OK|wx.CANCEL).ShowModal()
            if res==wx.ID_OK:
                part = rest.api.find_part(partobj.part.id, with_storages=True)
                for part_storage in part.storages:
                    if part_storage.id==storageobj.storage.id:
                        part_storage.quantity = part_storage.quantity-self.spin_num_parts.Value
                        break
            
                partobj.part = rest.api.update_part(part.id, part)
                if part_storage.quantity<0:
                    part_storage.quantity = 0
                partobj.quantity = part_storage.quantity
                self.tree_storage_parts_manager.UpdateItem(partobj)
            else:
                return
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onSelectPartCallback(self, part_event):
        item = self.tree_storages.GetSelection()
        if item.IsOk()==False:
            return
        storageobj = self.tree_storages_manager.ItemToObject(item)
        if isinstance(storageobj, DataModelStorage)==False:
            return

        part = part_event.data
        # check if part already exist
        for data in self.tree_storage_parts_manager.data:
            if data.part.id==part.id:
                wx.MessageDialog(self, "%s already added, skipped" % part_event.data.name, "Error adding part", wx.OK | wx.ICON_ERROR).ShowModal()
                return

        # update storages on part
        part = rest.api.find_part(part.id, with_storages=True)
        if part.storages is None:
            part.storages = []
        part_storage = PartStorage()
        part_storage.id = storageobj.storage.id
        part_storage.quantity = self.spin_num_parts.Value
        part.storages.append(part_storage)
        part = rest.api.update_part(part.id, part)

        partobj = DataModelStoragePart(part, part_storage.quantity)
        self.tree_storage_parts_manager.AppendItem(None, partobj)
Exemplo n.º 7
0
class PartsFrame(PanelParts): 
    def __init__(self, parent): 
        super(PartsFrame, self).__init__(parent)
        
        # create categories list
        self.tree_categories_manager = helper.tree.TreeManager(self.tree_categories, context_menu=self.menu_category)
        self.tree_categories_manager.AddTextColumn("name")
        self.tree_categories_manager.AddTextColumn("description")
        self.tree_categories_manager.DropAccept(DataModelCategory, self.onTreeCategoriesDropCategory)
        self.tree_categories_manager.DropAccept(DataModelPart, self.onTreeCategoriesDropPart)
        self.tree_categories_manager.OnSelectionChanged = self.onTreeCategoriesSelChanged
        self.tree_categories_manager.OnItemBeforeContextMenu = self.onTreeCategoriesBeforeContextMenu

        # parts filters
        self.parts_filter = Filter(self.filters_panel, self.onButtonRemoveFilterClick)
        
        # create parts list
        self.tree_parts_manager = TreeManagerParts(self.tree_parts, context_menu=self.menu_part)
        self.tree_parts_manager.AddIntegerColumn("id")
        self.tree_parts_manager.AddTextColumn("name")
        self.tree_parts_manager.AddTextColumn("description")
        self.tree_parts_manager.AddIntegerColumn("comment")
        self.tree_parts_manager.AddTextColumn("symbol")
        self.tree_parts_manager.AddTextColumn("footprint")
        self.tree_parts_manager.OnSelectionChanged = self.onTreePartsSelChanged
        self.tree_parts_manager.OnColumnHeaderRightClick = self.onTreePartsColumnHeaderRightClick
        self.tree_parts_manager.DropAccept(DataModelPart, self.onTreePartsDropPart)
        self.tree_parts_manager.OnItemBeforeContextMenu = self.onTreePartsBeforeContextMenu
        
        # 
        # create edit part panel
        self.panel_edit_part = EditPartFrame(self.part_splitter)
        self.part_splitter.SplitHorizontally(self.part_splitter.Window1, self.panel_edit_part, 400)
        self.panel_edit_part.Bind( EVT_EDIT_PART_APPLY_EVENT, self.onEditPartApply )
        self.panel_edit_part.Bind( EVT_EDIT_PART_CANCEL_EVENT, self.onEditPartCancel )

        self.toolbar_part.ToggleTool(self.toggle_part_path.GetId(), True)

        # initial edit state
        self.show_part(None)
        self.edit_state = None
        self.show_categories = True
        
        self.load()
        
    def loadCategories(self):
        # clear all
        self.tree_categories_manager.ClearItems()
        
        # load categories
        categories = rest.api.find_parts_categories()

        # load tree
        to_add = []
        id_category_map = {}
        for category in categories:
            to_add.append(category)
        while len(to_add)>0:
            category = to_add[0]
            id_category_map[category.id] = DataModelCategory(category)
            to_add.pop(0)
            
            # add to symbol
            if category.parent:
                self.tree_categories_manager.AppendItem(id_category_map[category.parent.id], id_category_map[category.id])
            else:
                self.tree_categories_manager.AppendItem(None, id_category_map[category.id])
            
            # load childs
            if category.childs:
                for child in category.childs:
                    to_add.append(child)
        
    def loadParts(self):
        # clear all
        self.tree_parts_manager.ClearItems()
        
        # load parts
        parts = rest.api.find_parts( with_parameters=True, **self.parts_filter.query_filter())

        if self.show_categories:
            # load categories
            categories = {}
            for part in parts:
                if part.category:
                    category_name = part.category.path
                else:
                    category_name = "/"
    
                if categories.has_key(category_name)==False:
                    categories[category_name] = DataModelCategoryPath(part.category)
                    self.tree_parts_manager.AppendItem(None, categories[category_name])
                self.tree_parts_manager.AppendItem(categories[category_name], DataModelPart(part, self.tree_parts_manager.model.columns))
            
            for category in categories:
                self.tree_parts_manager.Expand(categories[category])
        else:
            for part in parts:
                self.tree_parts_manager.AppendItem(None, DataModelPart(part, self.tree_parts_manager.model.columns))
            
    def load(self):
        try:
            self.loadCategories()
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

        try:
            self.loadParts()
        except Exception as e:
            print_stack()
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def load_full_part(self, partobj):
        if partobj:
            # read whole part from server
            partobj.part = rest.api.find_part(partobj.part.id, with_offers=True, with_parameters=True, with_childs=True, with_distributors=True, with_manufacturers=True, with_storages=True, with_attachements=True)
        
    def show_part(self, part):
        # disable editing
        self.panel_edit_part.enable(False)
        # enable evrything else
        self.panel_category.Enabled = True
        self.panel_parts.Enabled = True
        # set part
        self.panel_edit_part.SetPart(part)
        
    def edit_part(self, part):
        self.show_part(part)
        # enable editing
        self.panel_edit_part.enable(True)
        # disable evrything else
        self.panel_category.Enabled = False
        self.panel_parts.Enabled = False
        
    def new_part(self):
        part = rest.model.PartNew()
        
        # set category
        item = self.tree_categories.GetSelection()
        if item.IsOk():
            category = self.tree_categories_manager.ItemToObject(item)
            if category.category:
                part.category = category.category

        self.edit_part(part)

    def export_parts(self):

        # exporters = plugin_loader.load_export_plugins()
        # wildcards = '|'.join([x.wildcard for x in exporters])
        # wildcards

        # exportpath=os.path.join(os.getcwd(),'test','TESTimportCSV.csv')
        # exportpath
        # base, ext = os.path.splitext(exportpath)

        # TODO: implement export
        exporters = plugin_loader.load_export_plugins()

        wildcards = '|'.join([x.wildcard for x in exporters])

        export_dialog = wx.FileDialog(self, "Export Parts", "", "",
                                      wildcards,
                                      wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

        if export_dialog.ShowModal() == wx.ID_CANCEL:
            return

        base, ext = os.path.splitext(export_dialog.GetPath())
        filt_idx = export_dialog.GetFilterIndex()
        # load parts
        parts = rest.api.find_parts(**self.parts_filter.query_filter())

        exporters[filt_idx]().export(base, parts)     
        self.edit_state = None

    def import_parts(self):

        importers = plugin_loader.load_import_plugins()
        wildcards = '|'.join([x.wildcard for x in importers])
        
        import_dialog = wx.FileDialog(self, "Import Parts", "", "",
                                      wildcards,
                                      wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)

        if import_dialog.ShowModal() == wx.ID_CANCEL:
            return

        base, ext = os.path.splitext(import_dialog.GetPath())
        filt_idx = import_dialog.GetFilterIndex()


        # set category
        item = self.tree_categories.GetSelection()
        if item.IsOk():
            category = self.tree_categories_manager.ItemToObject(item)
            if category.category:
                import_items = importers[filt_idx]().fetch(base, category.category, rest.model)
        progression_frame = ProgressionFrame(self, "Importing  parts ") ;
        progression_frame.Show()

        for i, importItem in enumerate(import_items):
            wx.Yield()

            part = rest.model.PartNew()
            # SET imported Parts Fields
            
            part.name = importItem.name
            part.description = importItem.description

            # Update progress indicator
            progression_frame.SetProgression(part.name, i+1, len(import_items))
            if progression_frame.Canceled():
                break


            if isinstance(importItem.footprint, str) and len(importItem.footprint) == 0:  # Blank Footprint
                part.footprint = None
            else:  # Determine or Create correct Footprint References
                searchparam = {'search': importItem.footprint}
                matching_footprints = rest.api.find_footprints(**searchparam)
                if len(matching_footprints)==0: # ADD new footprint
                    # Check Footprint Category: "Uncatagorized" exists
                    try:
                        footprintcategoryid = {i.name: i.id
                                               for i in
                                               rest.api.find_footprints_categories()}['Uncategorized']
                    except KeyError, e:  # Category 'Uncategorized' does not exist
                        print_stack()
                        # Create the "Uncategorized" category
                        category = rest.model.FootprintCategoryNew()
                        category.name = "Uncategorized"
                        category.description = 'imported footprint names not already defined'
                        category = rest.api.add_footprints_category(category)
                        footprintcategoryid = category.id
                    except:
                        print_stack()
                        # TODO: handle other errors cleanly
                        raise
                        pass

                    part.footprint = rest.model.FootprintNew()
                    part.footprint.category = rest.model.FootprintCategoryRef(id=footprintcategoryid)
                    part.footprint.name = importItem.footprint
                    part.footprint.description = u''
                    part.footprint.comment = u''

                    # update part on server
                    part.footprint = rest.api.add_footprint(part.footprint)
Exemplo n.º 8
0
class PartsFrame(PanelParts): 
    def __init__(self, parent): 
        super(PartsFrame, self).__init__(parent)
        
        # create categories list
        self.tree_categories_manager = helper.tree.TreeManager(self.tree_categories)
        self.tree_categories_manager.AddTextColumn("name")
        self.tree_categories_manager.AddTextColumn("description")
        self.tree_categories_manager.DropAccept(DataModelCategory, self.onTreeCategoriesDropCategory)
        self.tree_categories_manager.DropAccept(DataModelPart, self.onTreeCategoriesDropPart)
        self.tree_categories_manager.OnSelectionChanged = self.onTreeCategoriesSelChanged
        # parts filters
        self.parts_filter = Filter(self.filters_panel, self.onButtonRemoveFilterClick)
        
        # create parts list
        self.tree_parts_manager = TreeManagerParts(self.tree_parts)
        self.tree_parts_manager.AddIntegerColumn("id")
        self.tree_parts_manager.AddTextColumn("name")
        self.tree_parts_manager.AddTextColumn("description")
        self.tree_parts_manager.AddIntegerColumn("comment")
        self.tree_parts_manager.OnSelectionChanged = self.onTreePartsSelChanged
        self.tree_parts_manager.DropAccept(DataModelPart, self.onTreePartsDropPart)
        
        # 
        # create edit part panel
        self.panel_edit_part = EditPartFrame(self.part_splitter)
        self.part_splitter.SplitHorizontally(self.part_splitter.Window1, self.panel_edit_part, 400)
        self.panel_edit_part.Bind( EVT_EDIT_PART_APPLY_EVENT, self.onEditPartApply )
        self.panel_edit_part.Bind( EVT_EDIT_PART_CANCEL_EVENT, self.onEditPartCancel )

        # initial edit state
        self.show_part(None)
        self.edit_state = None
        
        self.load()
        
    def loadCategories(self):
        # clear all
        self.tree_categories_manager.ClearItems()
        
        # load categories
        categories = rest.api.find_parts_categories()

        # load tree
        to_add = []
        id_category_map = {}
        for category in categories:
            to_add.append(category)
        while len(to_add)>0:
            category = to_add[0]
            id_category_map[category.id] = DataModelCategory(category)
            to_add.pop(0)
            
            # add to model
            if category.parent:
                self.tree_categories_manager.AppendItem(id_category_map[category.parent.id], id_category_map[category.id])
            else:
                self.tree_categories_manager.AppendItem(None, id_category_map[category.id])
            
            # load childs
            if category.childs:
                for child in category.childs:
                    to_add.append(child)
        
    def loadParts(self):
        # clear all
        self.tree_parts_manager.ClearItems()
        
        # load parts
        parts = rest.api.find_parts(**self.parts_filter.query_filter())

        # load categories
        categories = {}
        for part in parts:
            if part.category:
                category_name = part.category.path
            else:
                category_name = "/"

            if categories.has_key(category_name)==False:
                categories[category_name] = DataModelCategoryPath(part.category)
                self.tree_parts_manager.AppendItem(None, categories[category_name])
            self.tree_parts_manager.AppendItem(categories[category_name], DataModelPart(part))
        
        for category in categories:
            self.tree_parts_manager.Expand(categories[category])
                
    def load(self):
        try:
            self.loadCategories()
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

        try:
            self.loadParts()
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def load_full_part(self, partobj):
        if partobj:
            # read whole part from server
            partobj.part = rest.api.find_part(partobj.part.id, with_offers=True, with_parameters=True, with_childs=True, with_distributors=True, with_manufacturers=True, with_storages=True, with_attachements=True)
        
    def show_part(self, part):
        # disable editing
        self.panel_edit_part.enable(False)
        # enable evrything else
        self.panel_category.Enabled = True
        self.panel_parts.Enabled = True
        # set part
        self.panel_edit_part.SetPart(part)
        
    def edit_part(self, part):
        self.show_part(part)
        # enable editing
        self.panel_edit_part.enable(True)
        # disable evrything else
        self.panel_category.Enabled = False
        self.panel_parts.Enabled = False
        
    def new_part(self):
        part = rest.model.PartNew()
        
        # set category
        item = self.tree_categories.GetSelection()
        if item.IsOk():
            category = self.tree_categories_manager.ItemToObject(item)
            if category.category:
                part.category = category.category

        self.edit_part(part)

    def GetMenus(self):
        return [{'title': 'Parts', 'menu': self.menu_parts}]

    def onButtonRefreshCategoriesClick( self, event ):
        self.loadCategories()

    def onButtonAddCategoryClick( self, event ):
        category = EditCategoryFrame(self).addCategory(rest.model.PartCategoryNew)
        if category:
            try:
                # retrieve parent item from selection
                parentitem = self.tree_categories.GetSelection()
                parentobj = None
                category.parent = None
                if parentitem:
                    parentobj = self.tree_categories_manager.ItemToObject(parentitem)
                    category.parent = parentobj.category
                    
                # create category on server
                category = rest.api.add_parts_category(category)
                # create category on treeview
                newitem = self.tree_categories_manager.AppendItem(parentobj, DataModelCategory(category)) 
                # add category to item element
                self.tree_categories_manager.SelectItem(newitem)
                self.onTreeCategoriesSelChanged(None)
            except Exception as e:
                wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonEditCategoryClick( self, event ):
        sel = self.tree_categories.GetSelection()
        if sel.IsOk()==False:
            return
        categoryobj = self.tree_categories_manager.ItemToObject(sel)
        if categoryobj is None:
            return
        category = EditCategoryFrame(self).editCategory(categoryobj.category)
        if not category is None:
            try:
                categoryobj.category = rest.api.update_parts_category(categoryobj.category.id, category)
                self.tree_categories_manager.UpdateItem(categoryobj)
                self.onTreeCategoriesSelChanged(None)
            except Exception as e:
                wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

    def onButtonRemoveCategoryClick( self, event ):
        sel = self.tree_categories.GetSelection()
        categoryobj = self.tree_categories_manager.ItemToObject(sel)
        if categoryobj is None:
            return
        try:
            res = wx.MessageDialog(self, "Remove category '"+categoryobj.category.name+"'", "Remove?", wx.OK|wx.CANCEL).ShowModal()
            if res==wx.ID_OK:
                rest.api.delete_parts_category(categoryobj.category.id)
                self.tree_categories_manager.DeleteItem(categoryobj.parent, categoryobj)
            else:
                return
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)



    def onButtonRemoveFilterClick( self, event ):
        button = event.GetEventObject()
        self.parts_filter.remove(button.GetName())
        self.tree_categories.UnselectAll()
        self.loadParts()


    def onTreeCategoriesSelChanged( self, event ):
        item = self.tree_categories.GetSelection()
        category = None
        if item.IsOk():
            category = self.tree_categories_manager.ItemToObject(item)
        # set category filter
        self.parts_filter.remove('category')
        if category:
            self.parts_filter.add('category', category.category.id, category.category.name)
        # apply new filter and reload
        self.loadParts()

    def onTreeCategoriesDropCategory(self, x, y, data):
        dest_categoryitem, _ = self.tree_categories.HitTest((x, y))
        try:
            source_category_id = data['id']
            source_category = rest.api.find_parts_category(source_category_id)
            source_categoryitem = helper.tree.TreeManager.drag_item
            source_categoryobj = self.tree_categories_manager.ItemToObject(source_categoryitem)
    
            dest_category = None
            dest_categoryobj = None
            if dest_categoryitem.IsOk():
                dest_categoryobj = self.tree_categories_manager.ItemToObject(dest_categoryitem)
                dest_category = dest_categoryobj.category
                if source_category_id==dest_category.id:
                    return wx.DragError
                source_category.parent = rest.model.PartCategoryRef(id=dest_category.id)
            else:
                # set if as root category
                source_category.parent = None
            
            # update on server
            category = rest.api.update_parts_category(source_category.id, source_category)

            # update tree model
            if source_categoryobj:
                self.tree_categories_manager.MoveItem(source_categoryobj.parent, dest_categoryobj, source_categoryobj)
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)

        return wx.DragMove

    def onTreeCategoriesDropPart(self, x, y, data):
        dest_categoryitem, _ = self.tree_categories.HitTest((x, y))

        try:
            source_part_id = data['id']
            source_part = rest.api.find_part(source_part_id)

            dest_category = None
            dest_categoryobj = None
            if dest_categoryitem.IsOk():
                dest_categoryobj = self.tree_categories_manager.ItemToObject(dest_categoryitem)
                dest_category = dest_categoryobj.category
                source_part.category = rest.model.PartCategoryRef(id=dest_category.id)
            else:
                # set if as root category
                source_part.category = None
            
            # update on server
            part = rest.api.update_part(source_part.id, source_part)
            
            # update tree model
            self.tree_parts_manager.DeletePart(source_part)
            self.tree_parts_manager.AppendPart(part)
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)
        return wx.DragMove


    def onTreePartsSelChanged( self, event ):
        item = self.tree_parts.GetSelection()
        part = None
        if not item.IsOk():
            return
        
        obj = self.tree_parts_manager.ItemToObject(item)
        if isinstance(obj, DataModelPart):
            self.load_full_part(obj)
            part = obj.part
        self.show_part(part)

    def onTreePartsDropPart(self, x, y, data):
        dest_item, _ = self.tree_parts.HitTest((x, y))
        if not dest_item.IsOk():
            return 
        dest_obj = self.tree_parts_manager.ItemToObject(dest_item)
        if isinstance(dest_obj, DataModelPart) and isinstance(dest_obj.parent, DataModelCategoryPath):
            try:
                source_part_id = data['id']
                source_partobj = self.tree_parts_manager.FindPart(source_part_id)
    
                dest_part = rest.api.find_part(dest_obj.part.id, with_childs=True)
                dest_part.childs.append(source_partobj.part)

                rest.api.update_part(dest_part.id, dest_part)

                # update tree model
                self.tree_parts_manager.AppendChildPart(dest_part, source_partobj.part)
            except Exception as e:
                wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)
            return wx.DragMove

            
    def onEditPartApply( self, event ):
        part = event.data
        try:
            if self.edit_state=='edit':
                # update part on server
                part = rest.api.update_part(part.id, part)
                self.tree_parts_manager.UpdatePart(part)
            elif self.edit_state=='add':
                part = rest.api.add_part(part)
                self.tree_parts_manager.AppendPart(part)
        except Exception as e:
            wx.MessageBox(format(e), 'Error', wx.OK | wx.ICON_ERROR)
            return
        self.edit_state = None
        self.show_part(part)
     
    def onEditPartCancel( self, event ):
        part = None
        item = self.tree_parts.GetSelection()
        if item.IsOk():
            partobj = self.tree_parts_manager.ItemToObject(item)
            self.load_full_part(partobj)
            part = partobj.part
        self.edit_state = None
        self.show_part(part)


    def onButtonAddPartClick( self, event ):
        self.edit_state = 'add'
        self.new_part()

    def onButtonEditPartClick( self, event ):
        item = self.tree_parts.GetSelection()
        if not item.IsOk():
            return
        obj = self.tree_parts_manager.ItemToObject(item)
        if isinstance(obj, DataModelCategoryPath):
            return
        self.load_full_part(obj)
        self.edit_state = 'edit'
        self.edit_part(obj.part)

    def onButtonRemovePartClick( self, event ):
        item = self.tree_parts.GetSelection()
        if not item.IsOk():
            return
        obj = self.tree_parts_manager.ItemToObject(item)
        if isinstance(obj, DataModelCategoryPath):
            return
        part = obj.part
        if isinstance(obj.parent, DataModelPart):
            parent = obj.parent.part
            res = wx.MessageDialog(self, "Remove part '"+part.name+"' from '"+parent.name+"'", "Remove?", wx.OK|wx.CANCEL).ShowModal()
            if res==wx.ID_OK:
                # remove selected part from subparts
                parent = rest.api.find_part(parent.id, with_childs=True)
                for child in parent.childs:
                    if child.id==part.id:
                        parent.childs.remove(child)

                #parent.childs.remove(part)
                rest.api.update_part(parent.id, parent)
                self.tree_parts_manager.DeleteChildPart(parent, part)
            else:
                return 
        else:
            res = wx.MessageDialog(self, "Remove part '"+part.name+"'", "Remove?", wx.OK|wx.CANCEL).ShowModal()
            if res==wx.ID_OK:
                # remove part
                rest.api.delete_part(part.id)
                self.tree_parts_manager.DeletePart(part)
            else:
                return
        self.show_part(None)
 
    def onSearchPartsTextEnter( self, event ):
        # set search filter
        self.parts_filter.remove('search')
        if self.search_parts.Value!='':
            self.parts_filter.add('search', self.search_parts.Value)
        # apply new filter and reload
        self.loadParts()
 
    def onSearchPartsButton(self, event):
        return self.onSearchPartsTextEnter(event)

    def onButtonRefreshPartsClick( self, event ):
        self.loadParts()

    def OnMenuItem( self, event ):
        # events are not distributed by the frame so we distribute them manually
        if event.GetId()==self.menu_parts_refresh_octopart.GetId():
            self.onMenuItemPartsRefreshOctopart(event)

    def onMenuItemPartsRefreshOctopart( self, event ):
        progression_frame = ProgressionFrame(self, "Refresh parts from Octopart") ;
        progression_frame.Show() ;
        self.Enabled = False 
        
        # get category
        sel = self.tree_categories.GetSelection()
        if sel.IsOk():
            categoryobj = self.tree_categories_manager.ItemToObject(sel)
        else:
            categoryobj = None
        if categoryobj is None:
            parts = rest.api.find_parts()
        else:
            parts = rest.api.find_parts(category=categoryobj.category.id)

        i = 1
        for part in parts:
            wx.Yield()
            
            if part.octopart and part.octopart!="":
                self.refresh_octopart(part)
            
            progression_frame.SetProgression(part.name, i, len(parts)) ;
            if progression_frame.Canceled():
                break
            
            i = i+1

        self.Enabled = True
        progression_frame.Destroy()
        
    
    def refresh_octopart(self, part):
#        print "Refresh octopart for", part.name
        
        # get full part
        part = rest.api.find_part(part.id, with_offers=True, with_parameters=True, with_distributors=True, with_manufacturers=True)
        
        # get octopart data
        q = PartsQuery()
        q.get(part.octopart)
        sleep(1)    # only one request per second allowed

        for octopart in q.results():
            print "octopart:", octopart.json
            if octopart.item().uid()==part.octopart_uid:
                print "Refresh", part.octopart
                self.octopart_to_part(octopart, part)
                # update part
                rest.api.update_part(part.id, part)

        return 
    
    def octopart_to_part(self, octopart, part):
        # convert octopart to part values
        octopart_extractor = OctopartExtractor(octopart)

        # import part fields
        part.name = octopart.item().mpn()
        part.description = octopart.snippet()
        if part.description is None:
            part.description = ""
            
        # set field octopart to indicatethat part was imported from octopart
        part.octopart = octopart.item().mpn()
        part.updated = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
        
        # import parameters
        for spec_name in octopart.item().specs():
            parameter = octopart_extractor.ExtractParameter(spec_name)            
            
            # check if parameter already exist
            for p in part.parameters:
                if p.name==parameter.name:
                    part.parameters.remove(p)
                    break
            part.parameters.append(parameter)
        
        # remove all offers from distributor prior to add new offers
        for offer in octopart.item().offers():
            distributor_name = offer.seller().name()
            if part.distributors is None:
                return 
            to_remove = []
            for distributor in part.distributors:
                if distributor.name==distributor_name:
                    to_remove.append(distributor)            
            # don't remove in previous loop to avoid missing elements
            for distributor in to_remove:
                part.distributors.remove(distributor)

        # import distributors
        part_distributors = {}
        for offer in octopart.item().offers():
            
            distributor_name = offer.seller().name()
            if part_distributors.has_key(distributor_name)==False:
                distributor = None
                try:
                    distributors = rest.api.find_distributors(name=distributor_name)
                    if len(distributors)>0:
                        distributor = distributors[0]
                    else:
                        # distributor does not exists, create it
                        distributor = rest.model.DistributorNew()
                        distributor.name = offer.seller().name()
                        distributor.website = offer.seller().homepage_url()
                        distributor.allowed = True
                        distributor = rest.api.add_distributor(distributor)
                        
                except Exception as e:
                    wx.MessageBox(format(e), 'Error with distributor %s'%distributor_name, wx.OK | wx.ICON_ERROR)
                
                if distributor:
                    part_distributor = rest.model.PartDistributor()
                    part_distributor.id = distributor.id
                    part_distributor.name = distributor.name
                    part_distributor.offers = []
                    part_distributors[distributor_name] = part_distributor
            
            if part_distributors.has_key(distributor_name):           
                for price_name in offer.prices():
                    for quantity in offer.prices()[price_name]:
                        part_offer = rest.model.PartOffer()
                        part_offer.name = distributor_name
                        part_offer.distributor = distributor
                        part_offer.currency = price_name
                        if offer.moq():
                            part_offer.packaging_unit = offer.moq()
                        else:
                            part_offer.packaging_unit = 1
                        part_offer.quantity = quantity[0]
                        part_offer.unit_price = float(quantity[1])
                        part_offer.sku = offer.sku()
                        part_distributors[distributor_name].offers.append(part_offer)
        # add part_distributors to part
        for distributor_name in part_distributors:
            part.distributors.append(part_distributors[distributor_name])
        
        # import manufacturer
        manufacturer_name = octopart.item().manufacturer().name()
        manufacturer = None
        part.manufacturers = []
        try:
            manufacturers = rest.api.find_manufacturers(name=manufacturer_name)
            if len(manufacturers)>0:
                manufacturer = manufacturers[0]
            else:
                # distributor does not exists, create it
                manufacturer = rest.model.Manufacturer()
                manufacturer.name = manufacturer_name
                manufacturer.website = octopart.item().manufacturer().homepage_url()
                manufacturer = rest.api.add_manufacturer(manufacturer)

            # add new manufacturer
            part_manufacturer = rest.model.PartManufacturer()
            part_manufacturer.name = manufacturer.name
            part_manufacturer.part_name = part.name
            part.manufacturers.append(part_manufacturer)
        except:
            wx.MessageBox('%s: unknown error retrieving manufacturer' % (manufacturer_name), 'Warning', wx.OK | wx.ICON_EXCLAMATION)