partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit 6692fd0e2d7fb470cfc8d57144c2754206be1d01
parent 91d6f315d38b2d9b9c45a21803658f5b7c6b2005
Author: Felicitus <felicitus@felicitus.org>
Date:   Mon, 20 Jun 2011 16:38:55 +0200

Merge branch 'CATEGORY-GENERICS'

Conflicts:
	frontend/js/Components/Footprint/FootprintEditor.js
	frontend/js/Models/Footprint.js
	src/de/RaumZeitLabor/PartKeepr/Footprint/Footprint.php
	src/de/RaumZeitLabor/PartKeepr/Footprint/FootprintManager.php
	src/de/RaumZeitLabor/PartKeepr/Footprint/FootprintService.php

Diffstat:
Mfrontend/css/PartKeepr.css | 4++++
Mfrontend/js/Components/CategoryEditor/CategoryEditorTree.js | 104+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mfrontend/js/Components/CategoryEditor/CategoryEditorWindow.js | 3++-
Mfrontend/js/Components/CategoryStore.js | 2+-
Mfrontend/js/Components/CategoryTree.js | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mfrontend/js/Components/Distributor/DistributorEditor.js | 3+--
Mfrontend/js/Components/Distributor/DistributorEditorComponent.js | 4++--
Mfrontend/js/Components/Editor/Editor.js | 53+++++++++++++++++++++++++++--------------------------
Mfrontend/js/Components/Editor/EditorComponent.js | 132++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mfrontend/js/Components/Editor/EditorGrid.js | 69+++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mfrontend/js/Components/Footprint/FootprintAttachmentGrid.js | 2+-
Mfrontend/js/Components/Footprint/FootprintEditor.js | 70+++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mfrontend/js/Components/Footprint/FootprintEditorComponent.js | 26++++++++++++++++++++++++--
Dfrontend/js/Components/Footprint/FootprintGrid.js | 10----------
Mfrontend/js/Components/Manufacturer/ManufacturerEditor.js | 11++++++-----
Mfrontend/js/Components/Manufacturer/ManufacturerEditorComponent.js | 4++--
Mfrontend/js/Components/MessageLog.js | 2+-
Mfrontend/js/Components/Part/PartAttachmentGrid.js | 2+-
Mfrontend/js/Components/Part/PartDistributorGrid.js | 2+-
Mfrontend/js/Components/Part/PartEditorWindow.js | 4++++
Mfrontend/js/Components/Part/PartManufacturerGrid.js | 2+-
Mfrontend/js/Components/Part/PartParameterGrid.js | 2+-
Mfrontend/js/Components/Part/PartStockHistory.js | 2+-
Mfrontend/js/Components/Part/PartsManager.js | 7+++++--
Mfrontend/js/Components/PartUnit/PartUnitEditor.js | 3+--
Mfrontend/js/Components/PartUnit/PartUnitEditorComponent.js | 4++--
Mfrontend/js/Components/StorageLocation/StorageLocationEditor.js | 3+--
Mfrontend/js/Components/StorageLocation/StorageLocationEditorComponent.js | 4++--
Mfrontend/js/Components/Unit/UnitEditor.js | 1-
Mfrontend/js/Components/Unit/UnitEditorComponent.js | 4++--
Mfrontend/js/Components/User/UserEditorComponent.js | 6++++--
Mfrontend/js/Components/Widgets/CategoryComboBox.js | 2++
Afrontend/js/Components/Widgets/RemoteImageField.js | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afrontend/js/Components/Widgets/RemoteImageFieldLayout.js | 34++++++++++++++++++++++++++++++++++
Mfrontend/js/Dialogs/ExceptionWindow.js | 13++++++++++++-
Dfrontend/js/Models/Category.js | 14--------------
Mfrontend/js/Models/Distributor.js | 2+-
Mfrontend/js/Models/Footprint.js | 12+++++++-----
Mfrontend/js/Models/FootprintAttachment.js | 4++--
Mfrontend/js/Models/Manufacturer.js | 4++--
Mfrontend/js/Models/ManufacturerICLogo.js | 4++--
Mfrontend/js/Models/Message.js | 2+-
Mfrontend/js/Models/Part.js | 12++++++------
Mfrontend/js/Models/PartAttachment.js | 4++--
Mfrontend/js/Models/PartDistributor.js | 6+++---
Mfrontend/js/Models/PartManufacturer.js | 6+++---
Mfrontend/js/Models/PartParameter.js | 2+-
Mfrontend/js/Models/PartUnit.js | 2+-
Mfrontend/js/Models/SiPrefix.js | 2+-
Mfrontend/js/Models/StockEntry.js | 2+-
Mfrontend/js/Models/StorageLocation.js | 2+-
Mfrontend/js/Models/Unit.js | 4++--
Mfrontend/js/Models/User.js | 2+-
Mfrontend/js/PartKeepr.js | 26++++++++++++++------------
Mfrontend/js/Util/ServiceCall.js | 10+++-------
Mfrontend/js/bugfixes.js | 4++++
Asetup/data/footprints/BGA/CBGA-32.png | 0
Asetup/data/footprints/BGA/FCBGA-576.png | 0
Asetup/data/footprints/BGA/PBGA-119.png | 0
Asetup/data/footprints/BGA/PBGA-169.png | 0
Asetup/data/footprints/BGA/PBGA-225.png | 0
Asetup/data/footprints/BGA/PBGA-260.png | 0
Asetup/data/footprints/BGA/PBGA-297.png | 0
Asetup/data/footprints/BGA/PBGA-304.png | 0
Asetup/data/footprints/BGA/PBGA-316.png | 0
Asetup/data/footprints/BGA/PBGA-324.png | 0
Asetup/data/footprints/BGA/PBGA-385.png | 0
Asetup/data/footprints/BGA/PBGA-400.png | 0
Asetup/data/footprints/BGA/PBGA-484.png | 0
Asetup/data/footprints/BGA/PBGA-625.png | 0
Asetup/data/footprints/BGA/PBGA-676.png | 0
Asetup/data/footprints/footprints.yaml | 262+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/de/RaumZeitLabor/PartKeepr/Category/Category.php | 153-------------------------------------------------------------------------------
Dsrc/de/RaumZeitLabor/PartKeepr/Category/CategoryManager.php | 175-------------------------------------------------------------------------------
Dsrc/de/RaumZeitLabor/PartKeepr/Category/CategoryService.php | 132-------------------------------------------------------------------------------
Msrc/de/RaumZeitLabor/PartKeepr/Distributor/DistributorService.php | 2+-
Msrc/de/RaumZeitLabor/PartKeepr/Footprint/Footprint.php | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Asrc/de/RaumZeitLabor/PartKeepr/Footprint/FootprintImage.php | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/de/RaumZeitLabor/PartKeepr/Footprint/FootprintManager.php | 18++++++++++++++----
Msrc/de/RaumZeitLabor/PartKeepr/Footprint/FootprintService.php | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/de/RaumZeitLabor/PartKeepr/Manufacturer/Manufacturer.php | 3++-
Msrc/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerService.php | 2+-
Msrc/de/RaumZeitLabor/PartKeepr/Part/Part.php | 8+++++---
Msrc/de/RaumZeitLabor/PartKeepr/Part/PartManager.php | 6+++---
Msrc/de/RaumZeitLabor/PartKeepr/Part/PartService.php | 6+++---
Msrc/de/RaumZeitLabor/PartKeepr/PartKeepr.php | 19+++++++++++++++----
Msrc/de/RaumZeitLabor/PartKeepr/PartUnit/PartUnitService.php | 2+-
Msrc/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationService.php | 2+-
Msrc/de/RaumZeitLabor/PartKeepr/Unit/Unit.php | 19++++++++++++++++++-
Msrc/de/RaumZeitLabor/PartKeepr/Unit/UnitService.php | 2+-
Msrc/de/RaumZeitLabor/PartKeepr/User/UserService.php | 2+-
Msrc/de/RaumZeitLabor/PartKeepr/Util/BaseEntity.php | 12++++++++++++
Mtesting/SetupDatabase.php | 100++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mutil/classes/ExtJSFile.php | 2+-
94 files changed, 1239 insertions(+), 783 deletions(-)

diff --git a/frontend/css/PartKeepr.css b/frontend/css/PartKeepr.css @@ -61,4 +61,8 @@ td.o { td.o2 { background-color: #bbbbbb; +} + +.remoteimagefield { + border: 1px solid black; } \ No newline at end of file diff --git a/frontend/js/Components/CategoryEditor/CategoryEditorTree.js b/frontend/js/Components/CategoryEditor/CategoryEditorTree.js @@ -1,14 +1,22 @@ -PartKeepr.CategoryEditorTree = Ext.define("CategoryEditorTree", { +Ext.define("PartKeepr.CategoryEditorTree", { alias: 'widget.CategoryEditorTree', extend: 'PartKeepr.CategoryTree', - viewConfig: { - animate: false, - plugins: { - ptype: 'treeviewdragdrop', - ddGroup: 'CategoryTree' - } - }, + ddGroup: null, + categoryModel: null, + categoryService: null, initComponent: function () { + if (this.ddGroup !== null) { + Ext.apply(this, { + viewConfig: { + animate: false, + plugins: { + ptype: 'treeviewdragdrop', + ddGroup: this.ddGroup + } + }}); + } + + this.createToolbar(); this.callParent(); @@ -17,42 +25,16 @@ PartKeepr.CategoryEditorTree = Ext.define("CategoryEditorTree", { this.getView().on("itemcontextmenu", Ext.bind(this.onItemContextMenu, this)); this.createMenu(); + }, - onBeforeDrop: function (node, data, overModel, dropPosition, dropFunction, options) { - var draggedRecord = data.records[0]; - var droppedOn = this.getView().getRecord(node); - - if (draggedRecord.modelName == "Part") { - /* Move Part */ - var call = new PartKeepr.ServiceCall("Part", "movePart"); - - if (data.records.length > 1) { - var sources = []; - - for (var i=0;i<data.records.length;i++) { - sources.push(data.records[i].get("id")); - } - - call.setParameter("parts", sources); - } else { - call.setParameter("part", draggedRecord.get("id")); - } - - call.setParameter("targetCategory", droppedOn.get("id")); - call.setHandler(function () { - data.view.store.load(); - }); - call.doCall(); - - return false; - } + onBeforeDrop: function () { }, onCategoryDrop: function (node, data, model, pos) { var draggedRecord = data.records[0]; var droppedOn = this.getView().getRecord(node); - if (draggedRecord.modelName == "Part") { + if (!draggedRecord.isCategory) { return; } else { /* Must be a category */ @@ -67,7 +49,7 @@ PartKeepr.CategoryEditorTree = Ext.define("CategoryEditorTree", { this.getStore().sort("name", "ASC"); - var call = new PartKeepr.ServiceCall("Category", "moveCategory"); + var call = new PartKeepr.ServiceCall(this.categoryService, "moveCategory"); call.setLoadMessage(sprintf(i18n("Moving category %s..."), draggedRecord.get("name"))); call.setParameter("category", draggedRecord.get("id")); call.setParameter("target", targetRecord.get("id")); @@ -77,6 +59,7 @@ PartKeepr.CategoryEditorTree = Ext.define("CategoryEditorTree", { }, onItemContextMenu: function (view, record, item, index, event) { + if (!record.isCategory) { return; } var menu = this.menu; event.stopEvent(); @@ -121,12 +104,54 @@ PartKeepr.CategoryEditorTree = Ext.define("CategoryEditorTree", { ] }); }, + createToolbar: function () { + this.toolbarExpandButton = Ext.create("Ext.button.Button", { + icon: 'resources/silkicons/bullet_toggle_plus.png', + tooltip: i18n("Expand All"), + handler: this._onExpandClick, + scope: this + }); + + this.toolbarCollapseButton = Ext.create("Ext.button.Button", { + icon: 'resources/silkicons/bullet_toggle_minus.png', + tooltip: i18n("Collapse All"), + handler: this._onCollapseClick, + scope: this + }); + + this.toolbarReloadButton = Ext.create("Ext.button.Button", { + icon: 'resources/silkicons/arrow_refresh.png', + tooltip: i18n("Reload"), + handler: this._onReloadClick, + scope: this + }); + + this.toolbar = Ext.create("Ext.toolbar.Toolbar", { + enableOverflow: true, + dock: 'top', + items: [ this.toolbarExpandButton, this.toolbarCollapseButton, this.toolbarReloadButton ] + }); + + Ext.apply(this, { + dockedItems: [ this.toolbar ] + }); + }, + _onReloadClick: function () { + this.loadCategories(); + }, + _onExpandClick: function () { + this.getRootNode().firstChild.expand(true); + }, + _onCollapseClick: function () { + this.getRootNode().firstChild.collapse(true); + }, confirmCategoryDelete: function () { Ext.Msg.confirm(i18n("Confirm Category Delete"), sprintf(i18n("Do you really wish to delete the category %s?"), this.menu.record.get("name")), this.onCategoryDelete, this); }, showCategoryAddDialog: function () { var j = Ext.create("PartKeepr.CategoryEditorWindow", { record: null, + categoryModel: this.categoryModel, parent: this.menu.record.get("id"), listeners: { save: Ext.bind(this.onUpdateRecord, this) @@ -139,6 +164,7 @@ PartKeepr.CategoryEditorTree = Ext.define("CategoryEditorTree", { var j = Ext.create("PartKeepr.CategoryEditorWindow", { record: this.menu.record, parent: null, + categoryModel: this.categoryModel, listeners: { save: Ext.bind(this.onUpdateRecord, this) } @@ -169,7 +195,7 @@ PartKeepr.CategoryEditorTree = Ext.define("CategoryEditorTree", { }, onCategoryDelete: function (btn) { if (btn == "yes") { - var call = new PartKeepr.ServiceCall("Category", "deleteCategory"); + var call = new PartKeepr.ServiceCall(this.categoryService, "deleteCategory"); call.setLoadMessage(sprintf(i18n("Deleting category %s..."), this.menu.record.get("name"))); call.setParameter("id", this.menu.record.get("id")); call.setHandler(Ext.bind(this.onCategoryDeleted, this)); diff --git a/frontend/js/Components/CategoryEditor/CategoryEditorWindow.js b/frontend/js/Components/CategoryEditor/CategoryEditorWindow.js @@ -2,6 +2,7 @@ Ext.define('PartKeepr.CategoryEditorWindow', { extend: 'Ext.window.Window', border: false, width: 400, + categoryModel: null, initComponent: function () { this.form = Ext.create("PartKeepr.CategoryEditorForm"); @@ -20,7 +21,7 @@ Ext.define('PartKeepr.CategoryEditorWindow', { this.callParent(); - this.proxyRecord = Ext.create("PartKeepr.Category"); + this.proxyRecord = Ext.create(this.categoryModel); if (this.record) { this.proxyRecord.set("name", this.record.get("name")); diff --git a/frontend/js/Components/CategoryStore.js b/frontend/js/Components/CategoryStore.js @@ -1,7 +1,7 @@ PartKeepr.CategoryTreeStore = Ext.define("CategoryTreeStore", { extend: "Ext.data.TreeStore", - model: 'Category', + model: 'PartKeepr.Category', proxy: { type: 'ajax', url: PartKeepr.getBasePath()+'/Category', diff --git a/frontend/js/Components/CategoryTree.js b/frontend/js/Components/CategoryTree.js @@ -1,6 +1,8 @@ Ext.define("PartKeepr.CategoryTree", { alias: 'widget.CategoryTree', extend: 'Ext.tree.Panel', + categoryService: null, + categoryModel: null, displayField: 'name', sorters: [{ property: 'name', @@ -17,7 +19,8 @@ Ext.define("PartKeepr.CategoryTree", { id: "src", name: "Foo" }, - remoteSort: false + remoteSort: false, + folderSort: true }); this.callParent(); @@ -27,43 +30,79 @@ Ext.define("PartKeepr.CategoryTree", { this.loadCategories(); }, loadCategories: function () { - var call = new PartKeepr.ServiceCall("Category", "getAllCategories"); + var call = new PartKeepr.ServiceCall(this.categoryService, "getAllCategories"); call.setLoadMessage(i18n("Loading categories...")); - call.setHandler(Ext.bind(this.onCategoriesLoaded, this)); + call.setHandler(Ext.bind(this._onCategoriesLoaded, this)); call.doCall(); }, - onCategoriesLoaded: function (result) { - this.getRootNode().removeAll(true); + _onCategoriesLoaded: function (result) { + /* Store expand/collapse state for all nodes */ + var expandedNodes = this.getExpandedNodes(this.getRootNode()); - this.buildCategoryTree(this.getRootNode(), result); + this.getRootNode().removeAll(); + + this.buildCategoryTree(this.getRootNode(), result, expandedNodes); - this.getStore().sort("name"); this.loaded = true; this.getRootNode().expandChildren(); + this.getStore().sort("name", "ASC"); + this.fireEvent("categoriesLoaded"); + }, + getExpandedNodes: function (node) { + var ret = []; + if (node.get("expanded") === true) { + ret.push(node.get("id")); + } + for (var i=0;i<node.childNodes.length;i++) { + ret = ret.concat(this.getExpandedNodes(node.childNodes[i])); + } + return ret; }, - buildCategoryTree : function(root, data) { + buildCategoryTree : function(root, data, expandedNodes) { var nodeData = { - id : data.id, + id : data.id, name : data.name, tooltip : data.description }; + if (Ext.Array.contains(expandedNodes, data.id)) { + Ext.apply(nodeData, { + expanded: true + }); + } + // Hack to prevent our virtual root node from being dragged if (data.id == 1) { nodeData.allowDrag = false; } - //if (data.children.length === 0) { - //nodeData.leaf = true; - //} - var node = root.appendChild(nodeData); + /* We'd like to set leaf here. For some reason, the tree + * is stupid. + * + * If the node is a leaf, it's not possible to append children. I would + * have expected that the "leaf" flag is cleared when a child is appended. + * + * If the node is not a leaf, the node should (in theory) use the children + * count. However, it doesn't do that in our case and always shows the "expand" + * button unless clicked once. + */ + + /*if (data.children.length === 0) { + nodeData.leaf = true; + } else { + nodeData.leaf = false; + }*/ + + nodeData.leaf = false; + + var node = root.appendChild(Ext.create(this.categoryModel, nodeData)); for ( var i = 0; i < data.children.length; i++) { - this.buildCategoryTree(node, data.children[i]); + this.buildCategoryTree(node, data.children[i], expandedNodes); } } }); \ No newline at end of file diff --git a/frontend/js/Components/Distributor/DistributorEditor.js b/frontend/js/Components/Distributor/DistributorEditor.js @@ -22,6 +22,5 @@ Ext.define('PartKeepr.DistributorEditor', { name: 'comment', fieldLabel: i18n("Comment") }], - saveText: i18n("Save Distributor"), - model: 'PartKeepr.Distributor' + saveText: i18n("Save Distributor") }); diff --git a/frontend/js/Components/Distributor/DistributorEditorComponent.js b/frontend/js/Components/Distributor/DistributorEditorComponent.js @@ -1,12 +1,12 @@ Ext.define('PartKeepr.DistributorEditorComponent', { extend: 'PartKeepr.EditorComponent', alias: 'widget.DistributorEditorComponent', - gridClass: 'PartKeepr.DistributorGrid', + navigationClass: 'PartKeepr.DistributorGrid', editorClass: 'PartKeepr.DistributorEditor', newItemText: i18n("New Distributor"), + model: 'PartKeepr.Distributor', initComponent: function () { this.createStore({ - model: "Distributor", sorters: [{ property: 'name', direction:'ASC' diff --git a/frontend/js/Components/Editor/Editor.js b/frontend/js/Components/Editor/Editor.js @@ -13,7 +13,13 @@ Ext.define('PartKeepr.Editor', { defaults: { anchor: '100%', labelWidth: 150 + }, + + // If false, determinates if we should sync via the store or the record itself. + // If true, always syncs the record via it's own proxy. + syncDirect: false, + onFieldChange: function () { return; @@ -50,7 +56,7 @@ Ext.define('PartKeepr.Editor', { // Waiting for reply on http://www.sencha.com/forum/showthread.php?135142-Ext.form.Basic.loadRecord-causes-form-to-be-dirty&p=607588#post607588 }); - this.addEvents("editorClose", "startEdit"); + this.addEvents("editorClose", "startEdit", "itemSaved"); this.defaults.listeners = { "change": Ext.bind(this.onFieldChange, this) @@ -61,9 +67,9 @@ Ext.define('PartKeepr.Editor', { onCancelEdit: function () { this.fireEvent("editorClose", this); }, - newItem: function () { - var j = Ext.create(this.model); - + newItem: function (defaults) { + Ext.apply(defaults, {}); + var j = Ext.create(this.model, defaults); this.editItem(j); }, editItem: function (record) { @@ -85,26 +91,17 @@ Ext.define('PartKeepr.Editor', { } }, onItemSave: function () { - if (this.record) { - /* Check if this is an in-memory record */ - if (this.record.phantom === true) { - - /* Push form values into the record */ - this.getForm().updateRecord(this.record); - - /* Trigger the save */ - this.record.save({ - success: function (record) { - this.record = record; - - // Reload the store + this.getForm().updateRecord(this.record); + + this.record.save({ + callback: this._onSave, + scope: this + }); + +/* this.store.load({ scope : this, callback: function(records, operation, success) { - /* If the store contains our record, start - * editing with the store's record, since it handles - * syncing for us. - */ for (i=0;i<records.length;i++) { if (records[i].get("id") == this.record.get("id")) { this.editItem(records[i]); @@ -118,16 +115,20 @@ Ext.define('PartKeepr.Editor', { } else { this.getForm().updateRecord(this.record); - /* If the store doesn't handle our record, - * do it on our own. - */ - if (this.record.dirty && !this.record.store) { + if ((this.record.dirty && !this.record.store) || this.syncDirect == true) { this.record.save(); } else { // Sync via the store this.store.sync(); } + + this.fireEvent("itemSaved", this.record); } - } + }*/ + + }, + _onSave: function (record) { + this.record = record; + this.fireEvent("itemSaved", this.record); } }); \ No newline at end of file diff --git a/frontend/js/Components/Editor/EditorComponent.js b/frontend/js/Components/Editor/EditorComponent.js @@ -1,56 +1,101 @@ /** * @class PartKeepr.EditorComponent + * <p>The EditorComponent encapsulates an editing workflow. In general, we have four actions * for each object: create, update, delete, view. These actions stay exactly the same for each * distinct object.</p> - * <p>The EditorComponent is a border layout, which has a grid and a form.</p> + * <p>The EditorComponent is a border layout, which has a navigation and an editor area.</p> * @todo Document the editor system a bit better */ Ext.define('PartKeepr.EditorComponent', { extend: 'Ext.panel.Panel', alias: 'widget.EditorComponent', + + /** + * Misc layout settings + */ layout: 'border', - gridClass: null, - editorClass: null, padding: 5, - store: null, border: false, + + /** + * Specifies the class name of the navigation. The navigation is placed in the "west" region + * and needs to fire the event "itemSelect". The component listens on that event and + * creates an editor based on the selected record. + */ + navigationClass: null, + + /** + * Specifies the class name of the editor. + */ + editorClass: null, + + /** + * Contains the store for the item overview. + */ + store: null, + + /** + * Contains the associated model to load a record for. + */ + model: null, + + /** + * Some default text messages. Can be overridden by sub classes. + */ deleteMessage: i18n("Do you really wish to delete the item %s?"), deleteTitle: i18n("Delete Item"), newItemText: i18n("New Item"), + initComponent: function () { - this.grid = Ext.create(this.gridClass, { + /** + * Create the navigation panel + */ + this.navigation = Ext.create(this.navigationClass, { region: 'west', width: 265, split: true, - store: this.store, - listeners: { - "itemSelect": Ext.bind(this.startEdit, this) - } + store: this.store }); - this.grid.on("itemAdd", Ext.bind(this.newRecord, this)); - - this.grid.on("itemDelete", Ext.bind(this.confirmDelete, this)); + this.navigation.on("itemAdd", this.newRecord, this); + this.navigation.on("itemDelete", this.confirmDelete, this); + this.navigation.on("itemEdit", this.startEdit, this); + /** + * Create the editor panel + */ this.editorTabPanel = Ext.create("Ext.tab.Panel", { region: "center", layout: 'fit', plugins: Ext.create('Ext.ux.TabCloseMenu') }); - this.items = [ this.grid, this.editorTabPanel ]; + this.items = [ this.navigation, this.editorTabPanel ]; this.callParent(); }, - newRecord: function () { + /** + * Creates a new record. Creates a new instance of the editor. + */ + newRecord: function (defaults) { + Ext.apply(defaults, {}); + var editor = this.createEditor(this.newItemText); - editor.newItem(); + editor.newItem(defaults); this.editorTabPanel.add(editor).show(); }, - startEdit: function (r) { - var editor = this.findEditor(r.get("id")); + /** + * Instructs the component to edit a new record. + * @param {Record} record The record to edit + */ + startEdit: function (id) { + /* Search for an open editor for the current record. If we + * already have an editor, show the editor instead of loading + * a new record. + */ + var editor = this.findEditor(id); if (editor !== null) { editor.show(); @@ -58,13 +103,16 @@ Ext.define('PartKeepr.EditorComponent', { } // Still here? OK, we don't have an editor open. Create a new one - - - //this.editor.editItem(r); - editor = this.createEditor(r.getRecordName()); - editor.editItem(r); - this.editorTabPanel.add(editor).show(); - + var model = Ext.ModelManager.getModel(this.model); + + model.load(id, { + scope: this, + success: function(record, operation) { + editor = this.createEditor(record.getRecordName()); + editor.editItem(record); + this.editorTabPanel.add(editor).show(); + } + }); }, findEditor: function (id) { for (var i=0;i<this.editorTabPanel.items.getCount();i++) { @@ -79,6 +127,7 @@ Ext.define('PartKeepr.EditorComponent', { var editor = Ext.create(this.editorClass, { store: this.store, title: title, + model: this.model, closable: true, listeners: { editorClose: Ext.bind(function (m) { @@ -87,31 +136,43 @@ Ext.define('PartKeepr.EditorComponent', { } }); + editor.on("itemSaved", this.onItemSaved, this); return editor; }, confirmDelete: function () { - var r = this.grid.getSelectionModel().getLastSelected(); + var r = this.navigation.getSelectionModel().getLastSelected(); + var recordName; + + if (r.getRecordName) { + recordName = r.getRecordName(); + } else { + recordName = r.get("name"); + } Ext.Msg.confirm( this.deleteTitle, - sprintf(this.deleteMessage, r.getRecordName()), + sprintf(this.deleteMessage, recordName), function (but) { if (but == "yes") { - var editor = this.findEditor(r.get("id")); - - if (editor !== null) { - this.editorTabPanel.remove(editor); - } - - r.destroy(); - this.store.load(); + this.deleteRecord(r); } },this); }, + deleteRecord: function (r) { + var editor = this.findEditor(r.get("id")); + + if (editor !== null) { + this.editorTabPanel.remove(editor); + } + + r.destroy(); + this.store.load(); + }, // Creates a store. To be called from child's initComponent createStore: function (config) { Ext.Object.merge(config, { autoLoad: true, + model: this.model, autoSync: false, // Do not change. If true, new (empty) records would be immediately commited to the database. remoteFilter: true, remoteSort: true, @@ -133,5 +194,8 @@ Ext.define('PartKeepr.EditorComponent', { }, getStore: function () { return this.store; + }, + onItemSaved: function (record) { + this.navigation.syncChanges(record); } }); \ No newline at end of file diff --git a/frontend/js/Components/Editor/EditorGrid.js b/frontend/js/Components/Editor/EditorGrid.js @@ -42,6 +42,13 @@ Ext.define('PartKeepr.EditorGrid', { * @param {Object} record The deselected record */ "itemDeselect", + + /** + * @event itemEdit + * Fires if a record should be edited. + * @param {Object} record The record to edit + */ + "itemEdit", /** * @event itemDelete @@ -56,28 +63,10 @@ Ext.define('PartKeepr.EditorGrid', { "itemAdd"); - this.getSelectionModel().on("select", - Ext.bind(function (rsm, r, i) { - if (this.getSelectionModel().getCount() == 1) { - this.deleteButton.enable(); - } else { - this.deleteButton.disable(); - } - - this.fireEvent("itemSelect", r); - }, - this)); + this.getSelectionModel().on("select", this._onItemSelect, this); + this.getSelectionModel().on("deselect", this._onItemDeselect, this); - this.getSelectionModel().on("deselect", - Ext.bind(function (rsm, r, i) { - if (this.getSelectionModel().getCount() == 1) { - this.deleteButton.enable(); - } else { - this.deleteButton.disable(); - } - - this.fireEvent("itemDeselect", r); - }, this)); + this.on("itemclick", this._onItemEdit, this); this.deleteButton = Ext.create("Ext.button.Button", { text: (this.buttonTextMode !== "hide") ? this.deleteButtonText : '', @@ -125,5 +114,41 @@ Ext.define('PartKeepr.EditorGrid', { }); this.callParent(); -} + }, + syncChanges: function (record) { + // Simply reload the store for now + this.store.load(); + }, + /** + * Called when an item was selected. Enables/disables the delete button. + */ + _updateDeleteButton: function (selectionModel, record) { + /* Right now, we support delete on a single record only */ + if (this.getSelectionModel().getCount() == 1) { + this.deleteButton.enable(); + } else { + this.deleteButton.disable(); + } + }, + + /** + * Called when an item should be edited + */ + _onItemEdit: function (view, record) { + this.fireEvent("itemEdit", record.get("id")); + }, + /** + * Called when an item was selected + */ + _onItemSelect: function (selectionModel, record) { + this._updateDeleteButton(selectionModel, record); + this.fireEvent("itemSelect", record); + }, + /** + * Called when an item was deselected + */ + _onItemDeselect: function (selectionModel, record) { + this._updateDeleteButton(selectionModel, record); + this.fireEvent("itemDeselect", record); + } }); \ No newline at end of file diff --git a/frontend/js/Components/Footprint/FootprintAttachmentGrid.js b/frontend/js/Components/Footprint/FootprintAttachmentGrid.js @@ -2,5 +2,5 @@ Ext.define('PartKeepr.FootprintAttachmentGrid', { extend: 'PartKeepr.AttachmentGrid', alias: 'widget.FootprintAttachmentGrid', - model: "FootprintAttachment" + model: "PartKeepr.FootprintAttachment" }); \ No newline at end of file diff --git a/frontend/js/Components/Footprint/FootprintEditor.js b/frontend/js/Components/Footprint/FootprintEditor.js @@ -2,39 +2,68 @@ Ext.define('PartKeepr.FootprintEditor', { extend: 'PartKeepr.Editor', alias: 'widget.FootprintEditor', saveText: i18n("Save Footprint"), - model: 'PartKeepr.Footprint', + layout: 'column', + syncDirect: true, + labelWidth: 75, initComponent: function () { this.on("startEdit", this.onEditStart, this, { delay: 50 }); this.attachmentGrid = Ext.create("PartKeepr.FootprintAttachmentGrid", { height: 200, + anchor: '100%', border: true }); this.items = [{ - xtype: 'textfield', - name: 'name', - fieldLabel: i18n("Name") - }, { - xtype: 'textarea', - name: 'description', - fieldLabel: i18n("Description") - }, { - xtype: 'fieldcontainer', - fieldLabel: i18n("Attachments"), - items: this.attachmentGrid - }]; + columnWidth: 1, + minWidth: 500, + layout: 'anchor', + xtype: 'container', + margin: '0 5 0 0', + items: [ + { + xtype: 'textfield', + name: 'name', + labelWidth: 75, + anchor: '100%', + fieldLabel: i18n("Name") + },{ + labelWidth: 75, + xtype: 'textarea', + name: 'description', + anchor: '100%', + fieldLabel: i18n("Description") + },{ + labelWidth: 75, + xtype: 'fieldcontainer', + fieldLabel: i18n("Attachments"), + items: this.attachmentGrid + } + ] + },{ + width: 370, + height: 250, + xtype: 'remoteimagefield', + name: 'image_id', + imageType: 'footprint', + imageWidth: 256, + imageHeight: 256, + labelWidth: 75, + fieldLabel: i18n("Image") + }]; + this.on("itemSaved", this._onItemSaved, this); this.callParent(); }, + _onItemSaved: function (record) { + this.attachmentGrid.store.each(function (record) { + record.set("footprint_id", this.record.get("id")); + }, this); + + this.attachmentGrid.store.sync(); + }, onEditStart: function () { var store = this.record.attachments(); - store.load(); this.attachmentGrid.bindStore(store); - }, - onItemSave: function () { - this.callParent(); - - this.attachmentGrid.getStore().sync(); } -});- \ No newline at end of file +}); diff --git a/frontend/js/Components/Footprint/FootprintEditorComponent.js b/frontend/js/Components/Footprint/FootprintEditorComponent.js @@ -1,12 +1,12 @@ Ext.define('PartKeepr.FootprintEditorComponent', { extend: 'PartKeepr.EditorComponent', alias: 'widget.FootprintEditorComponent', - gridClass: 'PartKeepr.FootprintGrid', + navigationClass: 'PartKeepr.FootprintTree', editorClass: 'PartKeepr.FootprintEditor', newItemText: i18n("New Footprint"), + model: 'PartKeepr.Footprint', initComponent: function () { this.createStore({ - model: "Footprint", sorters: [{ property: 'name', direction:'ASC' @@ -14,5 +14,27 @@ Ext.define('PartKeepr.FootprintEditorComponent', { }); this.callParent(); + + }, + deleteRecord: function (r) { + var editor = this.findEditor(r.get("footprintId")); + + if (editor !== null) { + this.editorTabPanel.remove(editor); + } + + var call = new PartKeepr.ServiceCall("Footprint", "destroy"); + call.setParameter("id", r.get("footprintId")); + call.setHandler(Ext.bind(function () { + console.log("My footprint id is:"+r.get("footprintId")); + var oldRecordIndex = PartKeepr.getApplication().getFootprintStore().find("id", r.get("footprintId")); + + console.log(oldRecordIndex); + + PartKeepr.getApplication().getFootprintStore().removeAt(oldRecordIndex); + this.navigation.loadCategories(); }, this)); + call.doCall(); + + } }); \ No newline at end of file diff --git a/frontend/js/Components/Footprint/FootprintGrid.js b/frontend/js/Components/Footprint/FootprintGrid.js @@ -1,9 +0,0 @@ -Ext.define('PartKeepr.FootprintGrid', { - extend: 'PartKeepr.EditorGrid', - alias: 'widget.FootprintGrid', - columns: [ - {header: i18n("Footprint"), dataIndex: 'name', flex: 1} - ], - addButtonText: i18n("Add Footprint"), - deleteButtonText: i18n("Delete Footprint") -});- \ No newline at end of file diff --git a/frontend/js/Components/Manufacturer/ManufacturerEditor.js b/frontend/js/Components/Manufacturer/ManufacturerEditor.js @@ -2,7 +2,6 @@ Ext.define('PartKeepr.ManufacturerEditor', { extend: 'PartKeepr.Editor', alias: 'widget.ManufacturerEditor', saveText: i18n("Save Manufacturer"), - model: 'PartKeepr.Manufacturer', labelWidth: 150, initComponent: function () { this.on("startEdit", Ext.bind(this.onEditStart, this)); @@ -94,13 +93,16 @@ Ext.define('PartKeepr.ManufacturerEditor', { }]; + this.on("itemSaved", this.syncSlaveStores, this); this.callParent(); }, - onItemSave: function () { - this.callParent(); + syncSlaveStores: function () { + this.iclogoGrid.store.each(function (record) { + record.set("manufacturer_id", this.record.get("id")); + }, this); - this.iclogoGrid.getStore().sync(); + this.iclogoGrid.store.sync(); }, onFileUploaded: function (response) { this.iclogoGrid.getStore().add({ @@ -119,7 +121,6 @@ Ext.define('PartKeepr.ManufacturerEditor', { }, onEditStart: function () { var store = this.record.iclogos(); - store.load(); this.iclogoGrid.bindStore(store); } }); \ No newline at end of file diff --git a/frontend/js/Components/Manufacturer/ManufacturerEditorComponent.js b/frontend/js/Components/Manufacturer/ManufacturerEditorComponent.js @@ -1,12 +1,12 @@ Ext.define('PartKeepr.ManufacturerEditorComponent', { extend: 'PartKeepr.EditorComponent', alias: 'widget.ManufacturerEditorComponent', - gridClass: 'PartKeepr.ManufacturerGrid', + navigationClass: 'PartKeepr.ManufacturerGrid', editorClass: 'PartKeepr.ManufacturerEditor', newItemText: i18n("New Manufacturer"), + model: 'PartKeepr.Manufacturer', initComponent: function () { this.createStore({ - model: "Manufacturer", sorters: [{ property: 'name', direction:'ASC' diff --git a/frontend/js/Components/MessageLog.js b/frontend/js/Components/MessageLog.js @@ -1,7 +1,7 @@ Ext.define('PartKeepr.MessageLog', { extend: 'Ext.grid.Panel', store: { - model: "Message" + model: "PartKeepr.Message" }, columns: [ {header: i18n("Message"), dataIndex: 'message', flex: 1}, diff --git a/frontend/js/Components/Part/PartAttachmentGrid.js b/frontend/js/Components/Part/PartAttachmentGrid.js @@ -2,5 +2,5 @@ Ext.define('PartKeepr.PartAttachmentGrid', { extend: 'PartKeepr.AttachmentGrid', alias: 'widget.PartAttachmentGrid', - model: "PartAttachment" + model: "PartKeepr.PartAttachment" }); \ No newline at end of file diff --git a/frontend/js/Components/Part/PartDistributorGrid.js b/frontend/js/Components/Part/PartDistributorGrid.js @@ -4,7 +4,7 @@ Ext.define('PartKeepr.PartDistributorGrid', { border: false, initComponent: function () { this.store = Ext.create("Ext.data.Store", { - model: 'PartDistributor', + model: 'PartKeepr.PartDistributor', proxy: { type: 'memory', reader: { diff --git a/frontend/js/Components/Part/PartEditorWindow.js b/frontend/js/Components/Part/PartEditorWindow.js @@ -37,6 +37,10 @@ Ext.define('PartKeepr.PartEditorWindow', { r.parameters = []; } + if (!r.attachments) { + r.attachments = []; + } + this.editor.partDistributorGrid.getStore().loadData(r.distributors); this.editor.partManufacturerGrid.getStore().loadData(r.manufacturers); this.editor.partParameterGrid.getStore().loadData(r.parameters); diff --git a/frontend/js/Components/Part/PartManufacturerGrid.js b/frontend/js/Components/Part/PartManufacturerGrid.js @@ -4,7 +4,7 @@ Ext.define('PartKeepr.PartManufacturerGrid', { border: false, initComponent: function () { this.store = Ext.create("Ext.data.Store", { - model: 'PartManufacturer', + model: 'PartKeepr.PartManufacturer', proxy: { type: 'memory', reader: { diff --git a/frontend/js/Components/Part/PartParameterGrid.js b/frontend/js/Components/Part/PartParameterGrid.js @@ -4,7 +4,7 @@ Ext.define('PartKeepr.PartParameterGrid', { border: false, initComponent: function () { this.store = Ext.create("Ext.data.Store", { - model: 'PartParameter', + model: 'PartKeepr.PartParameter', proxy: { type: 'memory', reader: { diff --git a/frontend/js/Components/Part/PartStockHistory.js b/frontend/js/Components/Part/PartStockHistory.js @@ -40,7 +40,7 @@ Ext.define('PartKeepr.PartStockHistory', { autoSync: false, // Do not change. If true, new (empty) records would be immediately commited to the database. remoteFilter: false, remoteSort: false, - model: 'StockEntry', + model: 'PartKeepr.StockEntry', pageSize: -1}; this.store = Ext.create('Ext.data.Store', config); diff --git a/frontend/js/Components/Part/PartsManager.js b/frontend/js/Components/Part/PartsManager.js @@ -14,7 +14,7 @@ Ext.define('PartKeepr.PartManager', { * Create the store with the default sorter "name ASC" */ this.createStore({ - model: 'Part', + model: 'PartKeepr.Part', sorters: [{ property: 'name', direction:'ASC' @@ -22,9 +22,12 @@ Ext.define('PartKeepr.PartManager', { }); // Create the tree - this.tree = Ext.create("PartKeepr.CategoryEditorTree", { + this.tree = Ext.create("PartKeepr.PartCategoryTree", { region: 'west', + categoryModel: 'PartKeepr.PartCategory', + categoryService: 'PartCategory', split: true, + ddGroup: 'CategoryTree', width: 300, // @todo Make this configurable collapsible: true // We want to collapse the tree panel on small screens }); diff --git a/frontend/js/Components/PartUnit/PartUnitEditor.js b/frontend/js/Components/PartUnit/PartUnitEditor.js @@ -10,6 +10,5 @@ Ext.define('PartKeepr.PartUnitEditor', { name: 'shortName', fieldLabel: i18n("Short Name") }], - saveText: i18n("Save Part Unit"), - model: 'PartKeepr.PartUnit' + saveText: i18n("Save Part Unit") }); diff --git a/frontend/js/Components/PartUnit/PartUnitEditorComponent.js b/frontend/js/Components/PartUnit/PartUnitEditorComponent.js @@ -1,14 +1,14 @@ Ext.define('PartKeepr.PartUnitEditorComponent', { extend: 'PartKeepr.EditorComponent', alias: 'widget.PartUnitEditorComponent', - gridClass: 'PartKeepr.PartUnitGrid', + navigationClass: 'PartKeepr.PartUnitGrid', editorClass: 'PartKeepr.PartUnitEditor', newItemText: i18n("New Part Unit"), deleteMessage: i18n("Do you really wish to delete the part unit'%s'?"), deleteTitle: i18n("Delete Part Unit"), + model: 'PartKeepr.PartUnit', initComponent: function () { this.createStore({ - model: "PartUnit", sorters: [{ property: 'name', direction:'ASC' diff --git a/frontend/js/Components/StorageLocation/StorageLocationEditor.js b/frontend/js/Components/StorageLocation/StorageLocationEditor.js @@ -6,6 +6,5 @@ Ext.define('PartKeepr.StorageLocationEditor', { name: 'name', fieldLabel: i18n("Storage Location") }], - saveText: i18n("Save Storage Location"), - model: 'PartKeepr.StorageLocation' + saveText: i18n("Save Storage Location") }); \ No newline at end of file diff --git a/frontend/js/Components/StorageLocation/StorageLocationEditorComponent.js b/frontend/js/Components/StorageLocation/StorageLocationEditorComponent.js @@ -1,12 +1,12 @@ Ext.define('PartKeepr.StorageLocationEditorComponent', { extend: 'PartKeepr.EditorComponent', alias: 'widget.StorageLocationEditorComponent', - gridClass: 'PartKeepr.StorageLocationGrid', + navigationClass: 'PartKeepr.StorageLocationGrid', editorClass: 'PartKeepr.StorageLocationEditor', newItemText: i18n("New Storage Location"), + model: 'PartKeepr.StorageLocation', initComponent: function () { this.createStore({ - model: "StorageLocation", sorters: [{ property: 'name', direction:'ASC' diff --git a/frontend/js/Components/Unit/UnitEditor.js b/frontend/js/Components/Unit/UnitEditor.js @@ -2,7 +2,6 @@ Ext.define('PartKeepr.UnitEditor', { extend: 'PartKeepr.Editor', alias: 'widget.UnitEditor', saveText: i18n("Save Unit"), - model: 'PartKeepr.Unit', initComponent: function () { var sm = Ext.create('Ext.selection.CheckboxModel',{ diff --git a/frontend/js/Components/Unit/UnitEditorComponent.js b/frontend/js/Components/Unit/UnitEditorComponent.js @@ -1,14 +1,14 @@ Ext.define('PartKeepr.UnitEditorComponent', { extend: 'PartKeepr.EditorComponent', alias: 'widget.UnitEditorComponent', - gridClass: 'PartKeepr.UnitGrid', + navigationClass: 'PartKeepr.UnitGrid', editorClass: 'PartKeepr.UnitEditor', newItemText: i18n("New Unit"), deleteMessage: i18n("Do you really wish to delete the unit'%s'?"), deleteTitle: i18n("Delete Unit"), + model: 'PartKeepr.Unit', initComponent: function () { this.createStore({ - model: "Unit", sorters: [{ property: 'name', direction:'ASC' diff --git a/frontend/js/Components/User/UserEditorComponent.js b/frontend/js/Components/User/UserEditorComponent.js @@ -1,14 +1,16 @@ Ext.define('PartKeepr.UserEditorComponent', { extend: 'PartKeepr.EditorComponent', alias: 'widget.UserEditorComponent', - gridClass: 'PartKeepr.UserGrid', + navigationClass: 'PartKeepr.UserGrid', editorClass: 'PartKeepr.UserEditor', newItemText: i18n("New User"), deleteMessage: i18n("Do you really wish to delete the user '%s'?"), deleteTitle: i18n("Delete User"), + + model: 'PartKeepr.User', + initComponent: function () { this.createStore({ - model: "User", sorters: [{ property: 'username', direction:'ASC' diff --git a/frontend/js/Components/Widgets/CategoryComboBox.js b/frontend/js/Components/Widgets/CategoryComboBox.js @@ -22,6 +22,8 @@ Ext.define("PartKeepr.CategoryComboBox",{ self.picker = new PartKeepr.CategoryTree({ height:290, + categoryService: 'PartCategory', + categoryModel: 'PartKeepr.PartCategory', floating: true, focusOnToFront: false, shadow: false, diff --git a/frontend/js/Components/Widgets/RemoteImageField.js b/frontend/js/Components/Widgets/RemoteImageField.js @@ -0,0 +1,113 @@ +/** + * @class PartKeepr.RemoteImageField + * <p>The RemoteImageField is a form field which can be used to upload one image. It automatically + * displays the remote image by id, assigns a temporary ID if it's a new image so the model can be + * syncronized at once. + * + */ +Ext.define('PartKeepr.RemoteImageField', { + extend:'Ext.form.field.Base', + alias: 'widget.remoteimagefield', + + type: 'remoteimagefield', + + // Default width and height + imageWidth: 32, + imageHeight: 32, + + // The field template for rendering this field + fieldSubTpl: [ + '<img id="{id}" style="{size}" class="remoteimagefield"/>', + { + compiled: true, + disableFormats: true + }], + + /** + * Initializes the field + */ + initComponent : function(){ + this.minHeight = this.imageHeight; + this.minWidth = this.imageWidth; + + this.imageId = Ext.id("remoteimagefield"); + this.callParent(); + }, + /** + * Return the template data for this field + */ + getSubTplData: function() { + return { + size: 'height:'+this.imageHeight+"px;width:"+this.imageWidth+"px;", + imageid: this.imageId + }; + }, + /** + * Renders this field. + */ + onRender: function () { + var me = this, + renderSelectors = me.renderSelectors; + + Ext.applyIf(renderSelectors, me.getLabelableSelectors()); + + Ext.applyIf(renderSelectors, { + imgEl: 'img.remoteimagefield' + }); + + me.callParent(arguments); + }, + /** + * Applies the image URL to the element after rendering + */ + afterRender: function () { + this.imgEl.dom.src = this.getImageURL(); + + this.imgEl.on("click", this.onClick, this); + }, + onClick: function () { + var j = Ext.create("PartKeepr.FileUploadDialog", { imageUpload: true }); + j.on("fileUploaded", this.onFileUploaded, this); + j.show(); + }, + onFileUploaded: function (data) { + this.setValue("TMP:"+data.id); + }, + /** + * Returns the URL for the image field. Applies the temporary image if TMP: is + * found within the value. + */ + getImageURL: function () { + var idparam; + + if (strpos(this.value, "TMP:") !== false) { + idparam = "id=0&tmpId="+str_replace("TMP:","",this.value); + } else { + idparam = "id="+this.value; + } + + return PartKeepr.getImagePath() + "?"+idparam+"&type="+this.imageType+"&w="+this.imageWidth+"&h="+this.imageHeight+"&m=fitpadding"; + + }, + /** + * Sets a value for the field. If the value is numeric, we call the image service + * with the specified id and the specified type. If the value is a string and prefixed + * with TMP:, we use the type "TempImage" and pass the id which has to be specified after TMP:. + * + * Example + * TMP:12 would retrieve the temporary image with the ID 12 + * @param {Mixed} value The value to set + * @return {Ext.form.field.Field} this + */ + setValue: function(value) { + var me = this; + + this.setRawValue(value); + this.value = value; + if (this.rendered) { + this.imgEl.dom.src = this.getImageURL(); + } + return this; + } +}); + diff --git a/frontend/js/Components/Widgets/RemoteImageFieldLayout.js b/frontend/js/Components/Widgets/RemoteImageFieldLayout.js @@ -0,0 +1,33 @@ +// Not sure if this one is really needed. + +Ext.define('PartKeepr.RemoteImageFieldLayout', { + + /* Begin Definitions */ + + alias: ['layout.remoteimagefield'], + + extend: 'Ext.layout.component.field.Field', + + /* End Definitions */ + + type: 'remoteimagefield', + + sizeBodyContents: function(width, height) { + var me = this, + owner = me.owner, + inputEl = owner.inputEl, + triggerWrap = owner.triggerWrap, + triggerWidth = owner.getTriggerWidth(); + + // If we or our ancestor is hidden, we can get a triggerWidth calculation + // of 0. We don't want to resize in this case. + if (owner.hideTrigger || owner.readOnly || triggerWidth > 0) { + // Decrease the field's width by the width of the triggers. Both the field and the triggerWrap + // are floated left in CSS so they'll stack up side by side. + me.setElementSize(inputEl, Ext.isNumber(width) ? width - triggerWidth : width); + + // Explicitly set the triggerWrap's width, to prevent wrapping + triggerWrap.setWidth(triggerWidth); + } + } +});+ \ No newline at end of file diff --git a/frontend/js/Dialogs/ExceptionWindow.js b/frontend/js/Dialogs/ExceptionWindow.js @@ -90,7 +90,7 @@ Ext.define('PartKeepr.ExceptionWindow', { this.iconComponent.hide(); } }, - showException: function (exception) { + _showException: function (exception) { this.setIcon(Ext.MessageBox.ERROR); this.messageDiv.update(exception.message); @@ -117,5 +117,16 @@ Ext.define('PartKeepr.ExceptionWindow', { this.show(); + }, + + statics: { + showException: function (exception) { + if (!PartKeepr.ExceptionWindow.activeInstance) { + PartKeepr.ExceptionWindow.activeInstance = new PartKeepr.ExceptionWindow(); + } + + PartKeepr.ExceptionWindow.activeInstance._showException(exception); + } + } }); \ No newline at end of file diff --git a/frontend/js/Models/Category.js b/frontend/js/Models/Category.js @@ -1,14 +0,0 @@ -PartKeepr.Category = Ext.define("Category", { - extend: "Ext.data.Model", - fields: [ - { name: 'id', type: 'int' }, - { name: 'name', type: 'string' }, - { name: 'description', type: 'string' }, - { name: 'parent', type: 'int' } - ], - proxy: PartKeepr.getRESTProxy("Category"), - getRecordName: function () { - return this.get("name"); - } -}); - diff --git a/frontend/js/Models/Distributor.js b/frontend/js/Models/Distributor.js @@ -1,4 +1,4 @@ -PartKeepr.Distributor = Ext.define("Distributor", { +Ext.define("PartKeepr.Distributor", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, diff --git a/frontend/js/Models/Footprint.js b/frontend/js/Models/Footprint.js @@ -1,13 +1,16 @@ -PartKeepr.Footprint = Ext.define("Footprint", { +Ext.define("PartKeepr.Footprint", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, { name: 'name', type: 'string' }, - { name: 'description', type: 'string' } + { name: 'description', type: 'string' }, + // image_id needs to be a string because we need to be able to push TMP:<id> back + { name: 'image_id', type: 'string' }, + { name: 'category', type: 'int' } ], - hasMany: {model: 'FootprintAttachment', name: 'attachments'}, + hasMany: {model: 'PartKeepr.FootprintAttachment', name: 'attachments'}, proxy: PartKeepr.getRESTProxy("Footprint"), getRecordName: function () { return this.get("name"); } -});- \ No newline at end of file +}); diff --git a/frontend/js/Models/FootprintAttachment.js b/frontend/js/Models/FootprintAttachment.js @@ -1,4 +1,4 @@ -PartKeepr.FootprintAttachment = Ext.define("FootprintAttachment", { +Ext.define("PartKeepr.FootprintAttachment", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, @@ -10,6 +10,6 @@ PartKeepr.FootprintAttachment = Ext.define("FootprintAttachment", { { name: 'size', type: 'string' }, { name: 'tmp_id', type: 'int' } ], - belongsTo: { type: 'belongsTo', model: 'Footprint', primaryKey: 'id', foreignKey: 'footprint_id'}, + belongsTo: { type: 'belongsTo', model: 'PartKeepr.Footprint', primaryKey: 'id', foreignKey: 'footprint_id'}, proxy: PartKeepr.getRESTProxy("FootprintAttachment") }); \ No newline at end of file diff --git a/frontend/js/Models/Manufacturer.js b/frontend/js/Models/Manufacturer.js @@ -1,4 +1,4 @@ -PartKeepr.Manufacturer = Ext.define("Manufacturer", { +Ext.define("PartKeepr.Manufacturer", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, @@ -8,7 +8,7 @@ PartKeepr.Manufacturer = Ext.define("Manufacturer", { { name: 'address', type: 'string'}, { name: 'email', type: 'string'} ], - hasMany: {model: 'ManufacturerICLogo', name: 'iclogos'}, + hasMany: {model: 'PartKeepr.ManufacturerICLogo', name: 'iclogos'}, proxy: PartKeepr.getRESTProxy("Manufacturer"), getRecordName: function () { return this.get("name"); diff --git a/frontend/js/Models/ManufacturerICLogo.js b/frontend/js/Models/ManufacturerICLogo.js @@ -1,4 +1,4 @@ -PartKeepr.ManufacturerICLogo = Ext.define("ManufacturerICLogo", { +Ext.define("PartKeepr.ManufacturerICLogo", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, @@ -6,6 +6,6 @@ PartKeepr.ManufacturerICLogo = Ext.define("ManufacturerICLogo", { { name: 'type', type: 'string' }, { name: 'tmp_id', type: 'int' } ], - belongsTo: { type: 'belongsTo', model: 'Manufacturer', primaryKey: 'id', foreignKey: 'manufacturer_id'}, + belongsTo: { type: 'belongsTo', model: 'PartKeepr.Manufacturer', primaryKey: 'id', foreignKey: 'manufacturer_id'}, proxy: PartKeepr.getRESTProxy("ManufacturerICLogo") }); \ No newline at end of file diff --git a/frontend/js/Models/Message.js b/frontend/js/Models/Message.js @@ -1,4 +1,4 @@ -PartKeepr.Message = Ext.define("Message", { +Ext.define("PartKeepr.Message", { extend: "Ext.data.Model", fields: [ { name: 'message', type: 'string' }, diff --git a/frontend/js/Models/Part.js b/frontend/js/Models/Part.js @@ -1,4 +1,4 @@ -PartKeepr.Part = Ext.define("Part", { +Ext.define("PartKeepr.Part", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, @@ -31,11 +31,11 @@ PartKeepr.Part = Ext.define("Part", { { name: 'minStockLevel',type: 'int'} ], belongsTo: [ - { model: 'Manufacturer', primaryKey: 'id', foreignKey: 'manufacturer_id'}, - { model: 'StorageLocation', primaryKey: 'id', foreignKey: 'storageLocation_id'}, - { model: 'Footprint', primaryKey: 'id', foreignKey: 'footprint_id'}, - { model: 'Category', primaryKey: 'id', foreignKey: 'category_id'} + { model: 'PartKeepr.Manufacturer', primaryKey: 'id', foreignKey: 'manufacturer_id'}, + { model: 'PartKeepr.StorageLocation', primaryKey: 'id', foreignKey: 'storageLocation_id'}, + { model: 'PartKeepr.Footprint', primaryKey: 'id', foreignKey: 'footprint_id'}, + { model: 'PartKeepr.PartCategory', primaryKey: 'id', foreignKey: 'category_id'} ], - hasMany: { model: 'PartDistributor', name: 'distributors'}, + hasMany: { model: 'PartKeepr.PartDistributor', name: 'distributors'}, proxy: PartKeepr.getRESTProxy("Part") }); \ No newline at end of file diff --git a/frontend/js/Models/PartAttachment.js b/frontend/js/Models/PartAttachment.js @@ -1,4 +1,4 @@ -PartKeepr.PartAttachment = Ext.define("PartAttachment", { +Ext.define("PartKeepr.PartAttachment", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, @@ -9,6 +9,6 @@ PartKeepr.PartAttachment = Ext.define("PartAttachment", { { name: 'size', type: 'string' }, { name: 'tmp_id', type: 'int' } ], - belongsTo: { type: 'belongsTo', model: 'Part', primaryKey: 'id', foreignKey: 'part_id'}, + belongsTo: { type: 'belongsTo', model: 'PartKeepr.Part', primaryKey: 'id', foreignKey: 'part_id'}, proxy: PartKeepr.getRESTProxy("PartAttachment") }); \ No newline at end of file diff --git a/frontend/js/Models/PartDistributor.js b/frontend/js/Models/PartDistributor.js @@ -1,4 +1,4 @@ -PartKeepr.PartDistributor = Ext.define("PartDistributor", { +Ext.define("PartKeepr.PartDistributor", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, @@ -9,7 +9,7 @@ PartKeepr.PartDistributor = Ext.define("PartDistributor", { { name: 'orderNumber', type: 'string' }, { name: 'packagingUnit', type: 'int'} ], - belongsTo: { type: 'belongsTo', model: 'Part', primaryKey: 'id', foreignKey: 'part_id'}, - belongsTo: { type: 'belongsTo', model: 'Distributor', primaryKey: 'id', foreignKey: 'distributor_id'}, + belongsTo: { type: 'belongsTo', model: 'PartKeepr.Part', primaryKey: 'id', foreignKey: 'part_id'}, + belongsTo: { type: 'belongsTo', model: 'PartKeepr.Distributor', primaryKey: 'id', foreignKey: 'distributor_id'}, proxy: PartKeepr.getRESTProxy("PartDistributor") }); \ No newline at end of file diff --git a/frontend/js/Models/PartManufacturer.js b/frontend/js/Models/PartManufacturer.js @@ -1,4 +1,4 @@ -PartKeepr.PartManufacturer = Ext.define("PartManufacturer", { +Ext.define("PartKeepr.PartManufacturer", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, @@ -8,7 +8,7 @@ PartKeepr.PartManufacturer = Ext.define("PartManufacturer", { { name: 'manufacturer_name', type: 'string' }, { name: 'partNumber', type: 'string' } ], - belongsTo: { type: 'belongsTo', model: 'Part', primaryKey: 'id', foreignKey: 'part_id'}, - belongsTo: { type: 'belongsTo', model: 'Manufacturer', primaryKey: 'id', foreignKey: 'manufacturer_id'}, + belongsTo: { type: 'belongsTo', model: 'PartKeepr.Part', primaryKey: 'id', foreignKey: 'part_id'}, + belongsTo: { type: 'belongsTo', model: 'PartKeepr.Manufacturer', primaryKey: 'id', foreignKey: 'manufacturer_id'}, proxy: PartKeepr.getRESTProxy("PartManufacturer") }); diff --git a/frontend/js/Models/PartParameter.js b/frontend/js/Models/PartParameter.js @@ -1,4 +1,4 @@ -PartKeepr.PartParameter = Ext.define("PartParameter", { +Ext.define("PartKeepr.PartParameter", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, diff --git a/frontend/js/Models/PartUnit.js b/frontend/js/Models/PartUnit.js @@ -1,4 +1,4 @@ -PartKeepr.PartUnit = Ext.define("PartUnit", { +Ext.define("PartKeepr.PartUnit", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, diff --git a/frontend/js/Models/SiPrefix.js b/frontend/js/Models/SiPrefix.js @@ -1,4 +1,4 @@ -PartKeepr.SiPrefix = Ext.define("SiPrefix", { +Ext.define("PartKeepr.SiPrefix", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, diff --git a/frontend/js/Models/StockEntry.js b/frontend/js/Models/StockEntry.js @@ -1,4 +1,4 @@ -PartKeepr.StockEntry = Ext.define("StockEntry", { +Ext.define("PartKeepr.StockEntry", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, diff --git a/frontend/js/Models/StorageLocation.js b/frontend/js/Models/StorageLocation.js @@ -1,4 +1,4 @@ -PartKeepr.StorageLocation = Ext.define("StorageLocation", { +Ext.define("PartKeepr.StorageLocation", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, diff --git a/frontend/js/Models/Unit.js b/frontend/js/Models/Unit.js @@ -1,11 +1,11 @@ -PartKeepr.Unit = Ext.define("Unit", { +Ext.define("PartKeepr.Unit", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, { name: 'name', type: 'string'}, { name: 'symbol', type: 'string'} ], - hasMany: { model: 'SiPrefix', name: 'prefixes'}, + hasMany: { model: 'PartKeepr.SiPrefix', name: 'prefixes'}, proxy: PartKeepr.getRESTProxy("Unit"), getRecordName: function () { return this.get("name"); diff --git a/frontend/js/Models/User.js b/frontend/js/Models/User.js @@ -1,4 +1,4 @@ -PartKeepr.User = Ext.define("User", { +Ext.define("PartKeepr.User", { extend: "Ext.data.Model", fields: [ { id: 'id', name: 'id', type: 'int' }, diff --git a/frontend/js/PartKeepr.js b/frontend/js/PartKeepr.js @@ -24,49 +24,49 @@ Ext.application({ createGlobalStores: function () { this.storageLocationStore = Ext.create("Ext.data.Store", { - model: 'StorageLocation', + model: 'PartKeepr.StorageLocation', pageSize: -1, autoLoad: false }); this.footprintStore = Ext.create("Ext.data.Store", { - model: 'Footprint', + model: 'PartKeepr.Footprint', pageSize: -1, autoLoad: false }); this.siPrefixStore = Ext.create("Ext.data.Store", { - model: 'SiPrefix', + model: 'PartKeepr.SiPrefix', pageSize: -1, autoLoad: true }); this.distributorStore = Ext.create("Ext.data.Store", { - model: 'Distributor', + model: 'PartKeepr.Distributor', pageSize: -1, autoLoad: false }); this.manufacturerStore = Ext.create("Ext.data.Store", { - model: 'Manufacturer', + model: 'PartKeepr.Manufacturer', pageSize: -1, autoLoad: false }); this.partUnitStore = Ext.create("Ext.data.Store", { - model: 'PartUnit', + model: 'PartKeepr.PartUnit', pageSize: -1, autoLoad: false }); this.unitStore = Ext.create("Ext.data.Store", { - model: 'Unit', + model: 'PartKeepr.Unit', pageSize: -1, autoLoad: false }); @@ -192,7 +192,7 @@ Ext.application({ message: message, severity: severity, date: new Date() - }, 'Message'); + }, 'PartKeepr.Message'); this.messageLog.getStore().add(r); } @@ -244,8 +244,7 @@ PartKeepr.getRESTProxy = function (service) { try { var data = Ext.decode(response.responseText); - var j = new PartKeepr.ExceptionWindow(); - j.showException(data.exception); + PartKeepr.ExceptionWindow.showException(data.exception); } catch (ex) { var exception = { message: i18n("Critical Error"), @@ -255,8 +254,7 @@ PartKeepr.getRESTProxy = function (service) { }; - var jj = new PartKeepr.ExceptionWindow(); - jj.showException(exception); + PartKeepr.ExceptionWindow.showException(exception); } @@ -299,6 +297,10 @@ PartKeepr.getBasePath = function () { return "rest.php"; }; +PartKeepr.getImagePath = function () { + return "image.php"; +}; + PartKeepr.setMaxUploadSize = function (size) { PartKeepr.maxUploadSize = size; }; diff --git a/frontend/js/Util/ServiceCall.js b/frontend/js/Util/ServiceCall.js @@ -84,8 +84,7 @@ Ext.define('PartKeepr.ServiceCall', { }; - var j = new PartKeepr.ExceptionWindow(); - j.showException(exception); + PartKeepr.ExceptionWindow.showException(exception); return; } @@ -130,8 +129,7 @@ Ext.define('PartKeepr.ServiceCall', { try { var data = Ext.decode(response.responseText); - var j = new PartKeepr.ExceptionWindow(); - j.showException(data.exception); + PartKeepr.ExceptionWindow.showException(data.exception); } catch (ex) { var exception = { message: i18n("Critical Error"), @@ -140,9 +138,7 @@ Ext.define('PartKeepr.ServiceCall', { backtrace: response.responseText }; - - var jj = new PartKeepr.ExceptionWindow(); - jj.showException(exception); + PartKeepr.ExceptionWindow.showException(exception); } diff --git a/frontend/js/bugfixes.js b/frontend/js/bugfixes.js @@ -15,6 +15,10 @@ Ext.override(Ext.data.reader.Reader, }); +Ext.override(Ext.panel.Table, { + scrollDelta: 100 +}); + Ext.override(Ext.data.Connection, { /** * Inject session header. I haven't found a better way to do diff --git a/setup/data/footprints/BGA/CBGA-32.png b/setup/data/footprints/BGA/CBGA-32.png Binary files differ. diff --git a/setup/data/footprints/BGA/FCBGA-576.png b/setup/data/footprints/BGA/FCBGA-576.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-119.png b/setup/data/footprints/BGA/PBGA-119.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-169.png b/setup/data/footprints/BGA/PBGA-169.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-225.png b/setup/data/footprints/BGA/PBGA-225.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-260.png b/setup/data/footprints/BGA/PBGA-260.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-297.png b/setup/data/footprints/BGA/PBGA-297.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-304.png b/setup/data/footprints/BGA/PBGA-304.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-316.png b/setup/data/footprints/BGA/PBGA-316.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-324.png b/setup/data/footprints/BGA/PBGA-324.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-385.png b/setup/data/footprints/BGA/PBGA-385.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-400.png b/setup/data/footprints/BGA/PBGA-400.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-484.png b/setup/data/footprints/BGA/PBGA-484.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-625.png b/setup/data/footprints/BGA/PBGA-625.png Binary files differ. diff --git a/setup/data/footprints/BGA/PBGA-676.png b/setup/data/footprints/BGA/PBGA-676.png Binary files differ. diff --git a/setup/data/footprints/footprints.yaml b/setup/data/footprints/footprints.yaml @@ -0,0 +1,261 @@ +# Missing CSP BGA Footprints from http://www.analog.com/en/technical-library/packages/csp-chip-scale-package/csp-bga-ball-grid-array/index.html +# TODO: brazed cerdip packages from http://www.analog.com/en/technical-library/packages/dip-dual-inline-package/cerdip-side-or-bottom-brazed/index.html +# TODO: add gullwing lead DIP packages from http://www.analog.com/en/technical-library/packages/dip-dual-inline-package/dip-gullwing-leads/index.html +# TODO: add metal/hybrid DIP packages from http://www.analog.com/en/technical-library/packages/dip-dual-inline-package/metal-or-hybrid-dip/index.html + +CBGA-32: + description: 32-Lead Ceramic Ball Grid Array + image: BGA/CBGA-32.png + category: BGA/CBGA + attachments: + - url: http://www.analog.com/static/imported-files/packages/6438543BG_32_3.pdf + description: Outline +FCBGA-576: + description: 576-Ball Ball Grid Array, Thermally Enhanced + image: BGA/FCBGA-576.png + category: BGA/FCBGA + attachments: + - url: http://www.analog.com/static/imported-files/packages/3130038348142876336BP_576.pdf + description: Outline +# PBGA +PBGA-119: + description: 119-Ball Plastic Ball Grid Array + image: BGA/PBGA-119.png + category: BGA/PBGA + attachments: + - url: http://www.analog.com/static/imported-files/packages/41287574715699B_119.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/37136694b_119.pdf + description: Footprint +PBGA-169: + description: 169-Ball Plastic Ball Grid Array + image: BGA/PBGA-169.png + category: BGA/PBGA + attachments: + - url: http://www.analog.com/static/imported-files/packages/4508238598123917727B_169.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/42256861b_169.pdf + description: Footprint +PBGA-225: + description: 225-Ball Plastic a Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-225.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/PKG_PDF/BGA%20(B)/B_225_2.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/footprints/BGA%20(B)/B-225-2.pdf + description: Footprint +PBGA-260: + description: 260-Ball Plastic Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-260.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/4532729474093B_260.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/655582610b_260.pdf + description: Footprint +PBGA-297: + description: 297-Ball Plastic Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-297.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/251630103B_297.pdf + description: Outline +PBGA-304: + description: 304-Lead Plastic Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-304.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/3641645393185830319B_304.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/174089929b_304.pdf + description: Footprint +PBGA-316: + description: 316-Lead Plastic Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-316.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/61868185924959B_316.pdf + description: Outline +PBGA-324: + description: 324-Ball Plastic Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-324.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/454473177139443477109483B_324.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/17779623b_324.pdf + description: Footprint +PBGA-385: + description: 385-Lead Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-385.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/45557425288079B_385.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/804295803b_385.pdf + description: Footprint +PBGA-400: + description: 400-Ball Plastic Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-400.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/349373926B_400.pdf + description: Outline +PBGA-484: + description: 484-Ball Plastic Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-484.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/3235251121324624786157688555B484.pdf + description: Outline +PBGA-625: + description: 625-Ball Plastic Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-625.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/45005548173527848192875606315B625.pdf + description: Outline +PBGA-676: + description: 676-Ball Plastic Ball Grid Array + category: BGA/PBGA + image: BGA/PBGA-676.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/B_676.pdf + description: Outline +# SBGA +SBGA-256: + description: 256-Ball Ball Grid Array, Thermally Enhanced + category: BGA/PBGA + image: BGA/SBGA-256.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/287254833BP_256.pdf + description: Outline +SBGA-304: + description: 304-Ball Ball Grid Array, Thermally Enhanced + category: BGA/PBGA + image: BGA/SBGA-304.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/3733895948083BP_304.pdf + description: Outline +SBGA-432: + description: 432-Ball Ball Grid Array, Thermally Enhanced + category: BGA/PBGA + image: BGA/SBGA-432.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/99289205BP_432.pdf + description: Outline + +# Ceramic DIP +CerDIP-8: + description: 8-Lead Ceramic Dual In-Line Package + category: DIP/CERDIP + image: DIP/CERDIP-8.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/3925655241313314758Q_8.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/footprints/CERDIP/q-8.pdf + description: Footprint +CerDIP-14: + description: 14-Lead Ceramic Dual In-Line Package + category: DIP/CERDIP + image: DIP/CERDIP-14.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/393665681442905251546090Q_14.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/39808055q_14.pdf + description: Footprint +CerDIP-16: + description: 16-Lead Ceramic Dual In-Line Package + category: DIP/CERDIP + image: DIP/CERDIP-16.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/54083157002221Q_16.pdf + description: Outline +CerDIP-18: + description: 18-Lead Ceramic Dual In-Line Package + category: DIP/CERDIP + image: DIP/CERDIP-18.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/3949539816247344490Q_18.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/292506864q_18.pdf + description: Footprint +CerDIP-20: + description: 20-Lead Ceramic Dual In-Line Package + category: DIP/CERDIP + image: DIP/CERDIP-20.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/50516416473314Q_20.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/434715247d_20.pdf + description: Footprint +CerDIP-24 Narrow: + description: 24-Lead Ceramic Dual In-Line Package - Narrow Body + category: DIP/CERDIP + image: DIP/CERDIP-24-N.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/PKG_PDF/CERDIP(Q)/Q_24_1.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/274999619q_24.pdf + description: Footprint +CerDIP-24 Wide: + description: 24-Lead Ceramic Dual In-Line Package - Wide Body + category: DIP/CERDIP + image: DIP/CERDIP-24-W.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/PKG_PDF/CERDIP(Q)/Q_24_2.pdf + description: Outline +CerDIP-28: + description: 28-Lead Ceramic Dual In-Line Package + category: DIP/CERDIP + image: DIP/CERDIP-28.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/4045339666127361303Q_28_2.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/165461283q_28.pdf + description: Footprint +CerDIP-40: + description: 40-Lead Ceramic Dual In-Line Package + category: DIP/CERDIP + image: DIP/CERDIP-40.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/281170859Q_40.pdf + description: Outline + +# Plastic DIP (PDIP) +PDIP-8: + description: 8-Lead Plastic Dual In-Line Package + category: DIP/PDIP + image: DIP/PDIP-8.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/PKG_PDF/PDIP(N)/N_8.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/footprints/PDIP/n-8.pdf + description: Footprint +PDIP-14: + description: 14-Lead Plastic Dual In-Line Package + category: DIP/PDIP + image: DIP/PDIP-14.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/N_14.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/n-14.pdf + description: Footprint +PDIP-16: + description: 16-Lead Plastic Dual In-Line Package + category: DIP/PDIP + image: DIP/PDIP-16.png + attachments: + - url: http://www.analog.com/static/imported-files/packages/44768431550332N_16.pdf + description: Outline + - url: http://www.analog.com/static/imported-files/packages/59616100n_16.pdf + description: Footprint + +SOIC-N-EP-8: + description: 8-Lead Standard Small Outline Package, with Expose Pad + attachments: + - url: http://www.analog.com/static/imported-files/packages/PKG_PDF/SOIC_ED(RD)/RD_8_1.pdf + description: FOO + + + \ No newline at end of file diff --git a/src/de/RaumZeitLabor/PartKeepr/Category/Category.php b/src/de/RaumZeitLabor/PartKeepr/Category/Category.php @@ -1,153 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Category; - -use de\RaumZeitLabor\PartKeepr\Util\BaseEntity; -use de\RaumZeitLabor\PartKeepr\Util\Serializable; -use DoctrineExtensions\NestedSet\Node; - -declare(encoding = 'UTF-8'); - -/** - * @Entity - * @Table(indexes={@index(name="lft", columns={"lft"}),@index(name="rgt", columns={"rgt"})}) - * - * Represents a category within the system. - */ -class Category extends BaseEntity implements Node, Serializable { - /** - * The "left" property of the nested set - * @Column(type="integer") - * @var integer - */ - private $lft; - - /** - * The "right" property of the nested set - * @Column(type="integer") - * @var integer - */ - private $rgt; - - /** - * The name of the category - * @Column(length=128) - * @var string - */ - private $name; - - /** - * The description of the category - * @Column(type="text") - * @var string - */ - private $description; - - /** - * Holds the parent node ID. Note that this - * is not a persistant value, but rather calculated - * or set on the fly. - * @var int - */ - private $parent; - - /** - * Sets the name of this category - * @param string $name The name to set - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name of this category - * @return string The category name - */ - public function getName () { - return $this->name; - } - - /** - * Sets the parent for this category. - * - * @param int $id The parent node - */ - public function setParent ($id) { - $this->parent = $id; - } - - /** - * Returns the parent node for this node. - * @return int The parent node - */ - public function getParent () { - return $this->parent; - } - - /** - * Sets the description for this category - * @param string $description The description of this category - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the description of this category - * @return string The description - */ - public function getDescription () { - return $this->description; - } - - /** - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::getLeftValue() - */ - public function getLeftValue() { - return $this->lft; - } - - /** - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::setLeftValue() - */ - public function setLeftValue($lft) { - $this->lft = $lft; - } - - /** - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::getRightValue() - */ - public function getRightValue() { - return $this->rgt; - } - - /** - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::setRightValue() - */ - public function setRightValue($rgt) { - $this->rgt = $rgt; - } - - /** - * Serializes the entity. - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "description" => $this->getDescription() - ); - } - - /** - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::__toString() - */ - public function __toString () { - return $this->getName(); - } - -} diff --git a/src/de/RaumZeitLabor/PartKeepr/Category/CategoryManager.php b/src/de/RaumZeitLabor/PartKeepr/Category/CategoryManager.php @@ -1,174 +0,0 @@ -<?php -namespace de\raumzeitlabor\PartKeepr\Category; -declare(encoding = 'UTF-8'); - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Category\Category, - de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\Category\Exceptions\CategoryNotFoundException, - de\RaumZeitLabor\PartKeepr\PartKeepr; -use DoctrineExtensions\NestedSet\Manager; -use DoctrineExtensions\NestedSet\Config; -use DoctrineExtensions\NestedSet\NodeWrapper; - -class CategoryManager extends Singleton { - /** - * Holds the node manager - * @var object The node manager - */ - private $nodeManager; - - /** - * Returns the node manager. Creates it if it doesn't exist. - * @todo Can this method be made private? - * @return Manager The node manager - */ - public function getNodeManager () { - if (!$this->nodeManager) { - $config = new Config(PartKeepr::getEM(), 'de\RaumZeitLabor\PartKeepr\Category\Category'); - - $this->nodeManager = new Manager($config); - } - - return $this->nodeManager; - } - - /** - * Returns the child node id's for a given node id. - * @param integer $id The ID for which to retrieve the child nodes - * @return array An array of the children id's - * @todo Refactor this method name to indicate that it operates on IDs only. - */ - public function getChildNodes ($id) { - $category = $this->getCategory($id); - - $aData = array(); - - foreach ($category->getDescendants() as $cat) { - $aData[] = $cat->getNode()->getId(); - } - return $aData; - } - - /** - * Returns all categories. - * @return The category tree - */ - public function getAllCategories () { - return $this->getNodeManager()->fetchTree(1); - } - - /** - * Ensures that the root node exists. If not, this method creates it. - */ - public function ensureRootExists () { - /* Check if the root node exists */ - $rootNode = $this->getNodeManager()->fetchTree(1); - - if ($rootNode === null) { - $this->createRootNode(); - } - } - - /** - * Returns the root node for the category tree. - * @return The category root node - */ - public function getRootNode () { - return $this->getNodeManager()->fetchTree(1); - } - - /** - * Create the root node for the category tree. - */ - public function createRootNode () { - $rootNode = new Category(); - $rootNode->setName("Root Category"); - $rootNode->setDescription(""); - - $this->getNodeManager()->createRoot($rootNode); - } - - /** - * Adds a given category. - * @param Category $category The category to add to the tree - * @return Category the added category - */ - public function addCategory (Category $category) { - $parent = $category->getParent(); - - if ($parent == 0) { - $parent = $this->getRootNode(); - - } else { - $parent = PartKeepr::getEM()->find("de\RaumZeitLabor\PartKeepr\Category\Category", $parent); - - $parent = new NodeWrapper($parent, $this->getNodeManager()); - } - - return $parent->addChild($category); - } - - /** - * Deletes the given category ID. - * @param $id int The category id to delete - * @throws CategoryNotFoundException If the category wasn't found - */ - public function deleteCategory ($id) { - $category = PartKeepr::getEM()->find("de\RaumZeitLabor\PartKeepr\Category\Category", $id); - - - if ($category) { - try { - $category = new NodeWrapper($category, $this->getNodeManager()); - - if ($category->hasChildren()) { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains other categories."), $category->getNode()->getName())); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains other categories. Please move the categories or delete them first."), $category->getNode()->getName())); - - throw $exception; - } - $category->delete(); - } catch (\PDOException $e) { - if ($e->getCode() == "23000") { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains parts."), $category->getNode()->getName())); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains parts. Please move the parts to another category."), $category->getNode()->getName())); - - throw $exception; - } - } - - } else { - throw new CategoryNotFoundException($id); - } - } - - /** - * Returns the category with the given ID. - * @param int $id The category id - * @throws CategoryNotFoundException If the category wasn't found - */ - public function getCategory ($id) { - $category = PartKeepr::getEM()->find("de\RaumZeitLabor\PartKeepr\Category\Category", $id); - - - - if ($category) { - $category = new NodeWrapper($category, $this->getNodeManager()); - - return $category; - } else { - throw new CategoryNotFoundException($id); - } - } - - /** - * Returns the overall category count currently existing. - * @return int The amount of categories in the database - */ - public function getCategoryCount () { - $dql = "SELECT COUNT(c.id) FROM de\RaumZeitLabor\PartKeepr\Category\Category c"; - - return PartKeepr::getEM()->createQuery($dql)->getSingleScalarResult(); - } -}- \ No newline at end of file diff --git a/src/de/RaumZeitLabor/PartKeepr/Category/CategoryService.php b/src/de/RaumZeitLabor/PartKeepr/Category/CategoryService.php @@ -1,131 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Category; -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -declare(encoding = 'UTF-8'); - -use de\RaumZeitLabor\PartKeepr\Service\Service; -use de\RaumZeitLabor\PartKeepr\Category\CategoryManager; -use DoctrineExtensions\NestedSet\NodeWrapper; - - -class CategoryService extends Service { - - /** - * Returns all categories found in the system. - * @return array A serialized tree - */ - public function getCategories () { - $categories = CategoryManager::getInstance()->getAllCategories( - $this->getParameter("parent", 0)); - - return $this->serializeTree($categories); - } - - /** - * Moves the given category from one to another category. - */ - public function moveCategory () { - $this->requireParameter("category"); - $this->requireParameter("target"); - - $category = CategoryManager::getInstance()->getCategory($this->getParameter("category")); - - if (intval($this->getParameter("target", 0)) !== 0) { - - $parent = CategoryManager::getInstance()->getCategory($this->getParameter("target")); - - $category->moveAsLastChildOf($parent); - - } - } - - /** - * Deletes the given category. - */ - public function deleteCategory () { - $this->requireParameter("id"); - - CategoryManager::getInstance()->deleteCategory($this->getParameter("id")); - - return array("id" => $this->getParameter("id")); - } - - /** - * Updates the given category. - */ - public function update () { - $this->requireParameter("id"); - $this->requireParameter("name"); - - $category = CategoryManager::getInstance()->getCategory($this->getParameter("id")); - - $category->getNode()->setName($this->getParameter("name")); - $category->getNode()->setDescription($this->getParameter("description", "")); - - PartKeepr::getEM()->persist($category->getNode()); - - return array("data" => $this->serializeCategory($category)); - } - - public function create () { - $this->requireParameter("name"); - $this->requireParameter("parent"); - - $category = new Category; - $category->setName($this->getParameter("name")); - $category->setDescription($this->getParameter("description", "")); - $category->setParent($this->getParameter("parent")); - - $category = CategoryManager::getInstance()->addCategory($category); - - return array("data" => $this->serializeCategory($category)); - } - - private function serializeCategory ($category) { - $data = $category->getNode()->serialize(); - - if ($category->getParent() !== null) { - $data["parent"] = $category->getParent()->getNode()->getId(); - $data["parentName"] = $category->getParent()->getNode()->getName(); - } - - return $data; - } - - /** - * Returns all categories - */ - public function getAllCategories () { - return $this->serializeTree(CategoryManager::getInstance()->getAllCategories()); - } - - /** - * Serializes the given NodeWrapper as array including all children. - * @param NodeWrapper $node The category nodewrapper to serialize - * @throws \Exception - */ - public function serializeTree (NodeWrapper $node = null) { - if ($node == null) { - throw new \Exception("Node must not be null!"); - } - - $aData = $node->getNode()->serialize(); - - $aData["children"] = array(); - - if (count($node->getChildren()) == 0) { - $aData["leaf"] = true; - } else { - $aData["expanded"] = true; - } - - foreach ($node->getChildren() as $child) { - $aData["children"][] = $this->serializeTree($child); - - } - - return $aData; - } -} -?>- \ No newline at end of file diff --git a/src/de/RaumZeitLabor/PartKeepr/Distributor/DistributorService.php b/src/de/RaumZeitLabor/PartKeepr/Distributor/DistributorService.php @@ -17,7 +17,7 @@ class DistributorService extends Service implements RestfulService { */ public function get () { if ($this->hasParameter("id")) { - return DistributorManager::getInstance()->getDistributor($this->getParameter("id"))->serialize(); + return array("data" => DistributorManager::getInstance()->getDistributor($this->getParameter("id"))->serialize()); } else { if ($this->hasParameter("sort")) { $tmp = json_decode($this->getParameter("sort"), true); diff --git a/src/de/RaumZeitLabor/PartKeepr/Footprint/Footprint.php b/src/de/RaumZeitLabor/PartKeepr/Footprint/Footprint.php @@ -1,7 +1,7 @@ <?php namespace de\RaumZeitLabor\PartKeepr\Footprint; use de\RaumZeitLabor\PartKeepr\Util\Serializable; - +use de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory; use de\RaumZeitLabor\PartKeepr\Util\BaseEntity; declare(encoding = 'UTF-8'); @@ -22,11 +22,25 @@ class Footprint extends BaseEntity implements Serializable { * @var string */ private $description; + + /** + * The category of the footprint + * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory") + * @var Category + */ + private $category; + + /** + * Holds the footprint image + * @OneToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Footprint\FootprintImage",mappedBy="footprint",cascade={"persist", "remove"}) + * @var FootprintImage + */ + private $image; /** - * Holds the footprint attachments - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment",mappedBy="part",cascade={"persist", "remove"}) - * @var FootprintAttachment + * Holds the footprint attachments + * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment",mappedBy="footprint",cascade={"persist", "remove"}) + * @var FootprintAttachment */ private $attachments; @@ -71,6 +85,38 @@ class Footprint extends BaseEntity implements Serializable { } /** + * Sets the category for this footprint + * @param \de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory $category The category + */ + public function setCategory (FootprintCategory $category) { + $this->category = $category; + } + + /** + * Returns the category of this footprint + * @return FootprintCategory The footprint category + */ + public function getCategory () { + return $this->category; + } + + /** + * Sets the footprint image + * @param FootprintImage $image The footprint image + */ + public function setImage (FootprintImage $image) { + $this->image = $image; + } + + /** + * Returns the footprint image + * @return FootprintImage The footprint image + */ + public function getImage () { + return $this->image; + } + + /** * Returns the attachments for this footprint * @return ArrayCollection The attachments */ @@ -83,11 +129,13 @@ class Footprint extends BaseEntity implements Serializable { * @return array the serialized footprint */ public function serialize () { - $aAttachments = array(); - foreach ($this->getAttachments() as $attachment) { - $aAttachments[] = $attachment->serialize(); - } - - return array("id" => $this->getId(), "name" => $this->getName(), "description" => $this->getDescription(), "attachments" => $aAttachments); + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "description" => $this->getDescription(), + "image" => is_object($this->getImage()) ? $this->getImage()->serialize() : null, + "category" => is_object($this->getCategory()) ? $this->getCategory()->getId() : null, + "attachments" => $this->serializeChildren($this->getAttachments()) + ); } -}- \ No newline at end of file +} diff --git a/src/de/RaumZeitLabor/PartKeepr/Footprint/FootprintImage.php b/src/de/RaumZeitLabor/PartKeepr/Footprint/FootprintImage.php @@ -0,0 +1,52 @@ +<?php +namespace de\RaumZeitLabor\PartKeepr\Footprint; +use de\RaumZeitLabor\PartKeepr\Util\Serializable; + +declare(encoding = 'UTF-8'); + +use de\RaumZeitLabor\PartKeepr\Image\Image; + +/** + * Holds a footprint image + * @Entity + **/ +class FootprintImage extends Image implements Serializable { + /** + * The footprint object + * @OneToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Footprint\Footprint",inversedBy="image") + * @var Footprint + */ + private $footprint = null; + + /** + * Creates a new IC logo instance + */ + public function __construct () { + parent::__construct(Image::IMAGE_FOOTPRINT); + } + + /** + * Sets the footprint + * @param Footprint $footprint The footprint to set + */ + public function setFootprint (Footprint $footprint) { + $this->footprint = $footprint; + } + + /** + * Returns the footprint + * @return Footprint the footprint + */ + public function getFootprint () { + return $this->footprint; + } + + /** + * + * Serializes this ic logo + * @return array The serialized ic logo + */ + public function serialize () { + return array("id" => $this->getId(), "footprint_id" => $this->getFootprint()->getId()); + } +}+ \ No newline at end of file diff --git a/src/de/RaumZeitLabor/PartKeepr/Footprint/FootprintManager.php b/src/de/RaumZeitLabor/PartKeepr/Footprint/FootprintManager.php @@ -22,7 +22,9 @@ class FootprintManager extends Singleton { public function getFootprints ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("f.id, f.name, f.description")->from("de\RaumZeitLabor\PartKeepr\Footprint\Footprint","f"); + $qb->select("f.id, f.name, f.description, im.id AS image_id, ca.id AS category")->from("de\RaumZeitLabor\PartKeepr\Footprint\Footprint","f") + ->leftJoin("f.image", "im") + ->leftJoin("f.category", "ca"); if ($filter != "") { $qb = $qb->where("f.name LIKE :filter"); @@ -41,7 +43,7 @@ class FootprintManager extends Singleton { $result = $query->getResult(); $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(f.id)")->from("de\RaumZeitLabor\PartKeepr\Footprint\Footprint","f"); + $totalQueryBuilder->select("COUNT(f.id)")->from("de\RaumZeitLabor\PartKeepr\Footprint\Footprint","f")->leftJoin("f.image", "im"); @@ -72,8 +74,8 @@ class FootprintManager extends Singleton { PartKeepr::getEM()->flush(); } catch (\PDOException $e) { if ($e->getCode() == "23000") { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Footprint %s already exists!"), $footprint)); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to add the footprint %s, but a footprint with the same name already exists."), $footprint)); + $exception = new SerializableException(sprintf(PartKeepr::i18n("Footprint %s already exists!"), $name)); + $exception->setDetail(sprintf(PartKeepr::i18n("You tried to add the footprint %s, but a footprint with the same name already exists."), $name)); throw $exception; } else { @@ -107,6 +109,14 @@ class FootprintManager extends Singleton { } /** + * Loads a footprint by id + * @param int $id The footprint id + */ + public function getFootprint ($id) { + return Footprint::loadById($id); + } + + /** * Finds or creates a footprint by name. * * @param mixed $footprint Either the ID or the footprint's name to find diff --git a/src/de/RaumZeitLabor/PartKeepr/Footprint/FootprintService.php b/src/de/RaumZeitLabor/PartKeepr/Footprint/FootprintService.php @@ -1,5 +1,8 @@ <?php -namespace de\raumzeitlabor\PartKeepr\Footprint; +namespace de\RaumZeitLabor\PartKeepr\Footprint; +use de\RaumZeitLabor\PartKeepr\TempImage\TempImage; +use de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory; + declare(encoding = 'UTF-8'); use de\RaumZeitLabor\PartKeepr\Service\Service, @@ -14,7 +17,7 @@ class FootprintService extends Service implements RestfulService { */ public function get () { if ($this->hasParameter("id")) { - return FootprintManager::getInstance()->getFootprint($this->getParameter("id"))->serialize(); + return array("data" => FootprintManager::getInstance()->getFootprint($this->getParameter("id"))->serialize()); } else { if ($this->hasParameter("sort")) { $tmp = json_decode($this->getParameter("sort"), true); @@ -39,9 +42,28 @@ class FootprintService extends Service implements RestfulService { * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() */ public function create () { - $this->requireParameter("footprint"); + $this->requireParameter("name"); + + $fp = FootprintManager::getInstance()->addFootprint($this->getParameter("name")); + $fp->setDescription($this->getParameter("description")); + + if ($this->getParameter("image_id", false) !== false) { + if (strpos($this->getParameter("image_id"), "TMP:") !== false) { + $tmpImage = TempImage::loadById(str_replace("TMP:", "", $this->getParameter("image_id"))); + $image = new FootprintImage(); + $image->replace($tmpImage->getFilename()); + $image->setOriginalFilename($tmpImage->getOriginalFilename()); + + $fp->setImage($image); + $image->setFootprint($fp); + } + + } - $fp = FootprintManager::getInstance()->addFootprint($this->getParameter("footprint")); + try { + $footprintCategory = FootprintCategory::loadById($this->getParameter("category")); + $fp->setCategory($footprintCategory); + } catch (\Exception $e) {} return array("data" => $fp->serialize()); } @@ -52,11 +74,34 @@ class FootprintService extends Service implements RestfulService { */ public function update () { $this->requireParameter("id"); - $this->requireParameter("footprint"); - $footprint = FootprintManager::getInstance()->getFootprint($this->getParameter("id")); - $footprint->setName($this->getParameter("footprint")); + $this->requireParameter("name"); + $footprint = Footprint::loadById($this->getParameter("id")); + $footprint->setName($this->getParameter("name")); $footprint->setDescription($this->getParameter("description")); + if ($this->getParameter("image_id", false) !== false) { + if (strpos($this->getParameter("image_id"), "TMP:") !== false) { + $tmpImage = TempImage::loadById(str_replace("TMP:", "", $this->getParameter("image_id"))); + + $image= $footprint->getImage(); + + if ($image === null) { + $image = new FootprintImage(); + } + + $image->replace($tmpImage->getFilename()); + $image->setOriginalFilename($tmpImage->getOriginalFilename()); + $image->setFootprint($footprint); + + $footprint->setImage($image); + } + } + + try { + $footprintCategory = FootprintCategory::loadById($this->getParameter("category")); + $fp->setCategory($footprintCategory); + } catch (\Exception $e) {} + PartKeepr::getEM()->flush(); return array("data" => $footprint->serialize()); @@ -75,4 +120,16 @@ class FootprintService extends Service implements RestfulService { return array("data" => null); } + public function moveFootprint () { + $this->requireParameter("targetCategory"); + $this->requireParameter("id"); + + $footprint = Footprint::loadById($this->getParameter("id")); + $category = FootprintCategory::loadById($this->getParameter("targetCategory")); + + $footprint->setCategory($category); + + PartKeepr::getEM()->flush(); + } + } diff --git a/src/de/RaumZeitLabor/PartKeepr/Manufacturer/Manufacturer.php b/src/de/RaumZeitLabor/PartKeepr/Manufacturer/Manufacturer.php @@ -205,7 +205,8 @@ class Manufacturer extends BaseEntity implements Serializable { "url" => $this->getURL(), "address" => $this->getAddress(), "email" => $this->getEmail(), - "comment" => $this->getComment() + "comment" => $this->getComment(), + "iclogos" => $this->serializeChildren($this->getICLogos()) ); } } \ No newline at end of file diff --git a/src/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerService.php b/src/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerService.php @@ -17,7 +17,7 @@ class ManufacturerService extends Service implements RestfulService { */ public function get () { if ($this->hasParameter("id")) { - return ManufacturerManager::getInstance()->getManufacturer($this->getParameter("id"))->serialize(); + return array("data" => ManufacturerManager::getInstance()->getManufacturer($this->getParameter("id"))->serialize()); } else { if ($this->hasParameter("sort")) { $tmp = json_decode($this->getParameter("sort"), true); diff --git a/src/de/RaumZeitLabor/PartKeepr/Part/Part.php b/src/de/RaumZeitLabor/PartKeepr/Part/Part.php @@ -1,5 +1,7 @@ <?php namespace de\RaumZeitLabor\PartKeepr\Part; +use de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory; + use de\RaumZeitLabor\PartKeepr\Util\Serializable; use de\RaumZeitLabor\PartKeepr\Util\BaseEntity; @@ -16,7 +18,7 @@ use de\RaumZeitLabor\PartKeepr\PartKeepr, class Part extends BaseEntity implements Serializable { /** * The category of the part - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Category\Category") + * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory") * @var Category */ private $category; @@ -205,9 +207,9 @@ class Part extends BaseEntity implements Serializable { /** * Sets the category for this part - * @param \de\RaumZeitLabor\PartKeepr\Category\Category $category The category + * @param \de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory $category The category */ - public function setCategory (\de\RaumZeitLabor\PartKeepr\Category\Category $category) { + public function setCategory (PartCategory $category) { $this->category = $category; } diff --git a/src/de/RaumZeitLabor/PartKeepr/Part/PartManager.php b/src/de/RaumZeitLabor/PartKeepr/Part/PartManager.php @@ -27,7 +27,7 @@ declare(encoding = 'UTF-8'); use de\RaumZeitLabor\PartKeepr\Util\Singleton, de\RaumZeitLabor\PartKeepr\Footprint\Footprint, de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Category\CategoryManager, + de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerManager; class PartManager extends Singleton { @@ -79,7 +79,7 @@ class PartManager extends Singleton { $qb->andWhere("p.category = :category"); $qb->setParameter("category", $category); } else { - $childs = CategoryManager::getInstance()->getChildNodes($category); + $childs = PartCategoryManager::getInstance()->getChildNodes($category); $childs[] = $category; $qb->andWhere("p.category IN (".implode(",", $childs).")"); } @@ -177,7 +177,7 @@ class PartManager extends Singleton { } if (array_key_exists("category", $aParameters)) { - $category = CategoryManager::getInstance()->getCategory($aParameters["category"]); + $category = PartCategoryManager::getInstance()->getCategory($aParameters["category"]); $part->setCategory($category->getNode()); } diff --git a/src/de/RaumZeitLabor/PartKeepr/Part/PartService.php b/src/de/RaumZeitLabor/PartKeepr/Part/PartService.php @@ -8,7 +8,7 @@ use de\RaumZeitLabor\PartKeepr\Service\Service; use de\RaumZeitLabor\PartKeepr\Part\PartManager, de\RaumZeitLabor\PartKeepr\Stock\StockEntry, de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Category\Category, + de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory, de\RaumZeitLabor\PartKeepr\Session\SessionManager; class PartService extends Service implements RestfulService { @@ -65,13 +65,13 @@ class PartService extends Service implements RestfulService { /* We are moving multiple parts */ foreach ($this->getParameter("parts") as $part) { $part = Part::loadById($part); - $category = Category::loadById($this->getParameter("targetCategory")); + $category = PartCategory::loadById($this->getParameter("targetCategory")); $part->setCategory($category); } } else { $part = Part::loadById($this->getParameter("part")); - $category = Category::loadById($this->getParameter("targetCategory")); + $category = PartCategory::loadById($this->getParameter("targetCategory")); $part->setCategory($category); diff --git a/src/de/RaumZeitLabor/PartKeepr/PartKeepr.php b/src/de/RaumZeitLabor/PartKeepr/PartKeepr.php @@ -172,29 +172,40 @@ class PartKeepr { return array( 'de\RaumZeitLabor\PartKeepr\User\User', 'de\RaumZeitLabor\PartKeepr\Session\Session', + 'de\RaumZeitLabor\PartKeepr\Footprint\Footprint', + 'de\RaumZeitLabor\PartKeepr\Footprint\FootprintImage', 'de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment', - 'de\RaumZeitLabor\PartKeepr\Category\Category', + 'de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory', + 'de\RaumZeitLabor\PartKeepr\Part\Part', 'de\RaumZeitLabor\PartKeepr\Part\PartUnit', 'de\RaumZeitLabor\PartKeepr\Part\PartManufacturer', 'de\RaumZeitLabor\PartKeepr\Part\PartDistributor', 'de\RaumZeitLabor\PartKeepr\Part\PartImage', 'de\RaumZeitLabor\PartKeepr\Part\PartAttachment', + 'de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory', + 'de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation', + 'de\RaumZeitLabor\PartKeepr\Stock\StockEntry', + 'de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer', + 'de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo', + 'de\RaumZeitLabor\PartKeepr\Distributor\Distributor', + 'de\RaumZeitLabor\PartKeepr\Image\Image', 'de\RaumZeitLabor\PartKeepr\Image\CachedImage', 'de\RaumZeitLabor\PartKeepr\TempImage\TempImage', - 'de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo', + + 'de\RaumZeitLabor\PartKeepr\UploadedFile\TempUploadedFile', + 'de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshot', 'de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshotUnit', 'de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix', 'de\RaumZeitLabor\PartKeepr\Unit\Unit', - 'de\RaumZeitLabor\PartKeepr\PartParameter\PartParameter', - 'de\RaumZeitLabor\PartKeepr\UploadedFile\TempUploadedFile' + 'de\RaumZeitLabor\PartKeepr\PartParameter\PartParameter' ); } diff --git a/src/de/RaumZeitLabor/PartKeepr/PartUnit/PartUnitService.php b/src/de/RaumZeitLabor/PartKeepr/PartUnit/PartUnitService.php @@ -12,7 +12,7 @@ use de\RaumZeitLabor\PartKeepr\PartKeepr, class PartUnitService extends Service implements RestfulService { public function get () { if ($this->hasParameter("id")) { - return PartUnitManager::getInstance()->getPartUnit($this->getParameter("id"))->serialize(); + return array("data" => PartUnitManager::getInstance()->getPartUnit($this->getParameter("id"))->serialize()); } else { if ($this->hasParameter("sort")) { $tmp = json_decode($this->getParameter("sort"), true); diff --git a/src/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationService.php b/src/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationService.php @@ -14,7 +14,7 @@ class StorageLocationService extends Service implements RestfulService { public function get () { if ($this->hasParameter("id")) { - return StorageLocationManager::getInstance()->getStorageLocation($this->getParameter("id"))->serialize(); + return array("data" => StorageLocationManager::getInstance()->getStorageLocation($this->getParameter("id"))->serialize()); } else { if ($this->hasParameter("sort")) { $tmp = json_decode($this->getParameter("sort"), true); diff --git a/src/de/RaumZeitLabor/PartKeepr/Unit/Unit.php b/src/de/RaumZeitLabor/PartKeepr/Unit/Unit.php @@ -1,5 +1,7 @@ <?php namespace de\RaumZeitLabor\PartKeepr\Unit; +use de\RaumZeitLabor\PartKeepr\Util\Serializable; + use de\RaumZeitLabor\PartKeepr\Util\BaseEntity; declare(encoding = 'UTF-8'); @@ -14,7 +16,7 @@ use de\RaumZeitLabor\PartKeepr\PartKeepr, * * @Entity **/ -class Unit extends BaseEntity { +class Unit extends BaseEntity implements Serializable { /** * The name of the unit (e.g. Volts, Ampere, Farad, Metres) * @Column(type="string") @@ -86,4 +88,19 @@ class Unit extends BaseEntity { public function getPrefixes () { return $this->prefixes; } + + /** + * Serializes the user object and returns it as array, suitable + * to process via json_encode. + * @param none + * @return array An array containing the object information + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "symbol" => $this->getSymbol(), + "prefixes" => $this->serializeChildren($this->getPrefixes()) + ); + } } \ No newline at end of file diff --git a/src/de/RaumZeitLabor/PartKeepr/Unit/UnitService.php b/src/de/RaumZeitLabor/PartKeepr/Unit/UnitService.php @@ -13,7 +13,7 @@ use de\RaumZeitLabor\PartKeepr\PartKeepr, class UnitService extends Service implements RestfulService { public function get () { if ($this->hasParameter("id")) { - return UnitManager::getInstance()->getUnit($this->getParameter("id"))->serialize(); + return array("data" => UnitManager::getInstance()->getUnit($this->getParameter("id"))->serialize()); } else { if ($this->hasParameter("sort")) { $tmp = json_decode($this->getParameter("sort"), true); diff --git a/src/de/RaumZeitLabor/PartKeepr/User/UserService.php b/src/de/RaumZeitLabor/PartKeepr/User/UserService.php @@ -21,7 +21,7 @@ class UserService extends AdminService implements RestfulService { */ public function get () { if ($this->hasParameter("id")) { - return UserManager::getInstance()->getUser($this->getParameter("id"))->serialize(); + return array("data" => UserManager::getInstance()->getUser($this->getParameter("id"))->serialize()); } else { if ($this->hasParameter("sort")) { $tmp = json_decode($this->getParameter("sort"), true); diff --git a/src/de/RaumZeitLabor/PartKeepr/Util/BaseEntity.php b/src/de/RaumZeitLabor/PartKeepr/Util/BaseEntity.php @@ -22,6 +22,18 @@ class BaseEntity { return $this->id; } + public function serializeChildren (\Doctrine\Common\Collections\Collection $array) { + $aData = array(); + $aData["totalCount"] = $array->count(); + $aData["data"] = array(); + + foreach ($array as $item) { + $aData["data"][] = $item->serialize(); + } + + return array("response" => $aData); + } + /** * Loads the entity from the database. * @param integer $id The entity's id diff --git a/testing/SetupDatabase.php b/testing/SetupDatabase.php @@ -1,5 +1,13 @@ <?php namespace de\RaumZeitLabor\PartKeepr\Tests; +use de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory; + +use de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategoryManager; + +use de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment; + +use de\RaumZeitLabor\PartKeepr\Footprint\FootprintImage; + use de\RaumZeitLabor\PartKeepr\PartParameter\PartParameter; use de\RaumZeitLabor\PartKeepr\Part\PartAttachment; @@ -18,12 +26,12 @@ use de\RaumZeitLabor\PartKeepr\Footprint\Footprint; use de\RaumZeitLabor\PartKeepr\Footprint\FootprintManager; use de\RaumZeitLabor\PartKeepr\PartKeepr; use de\RaumZeitLabor\PartKeepr\Part\PartUnit; -use de\RaumZeitLabor\PartKeepr\Category\Category; +use de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory; use de\RaumZeitLabor\PartKeepr\Part\Part; use de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation; use de\RaumZeitLabor\PartKeepr\Stock\StockEntry; -use de\RaumZeitLabor\PartKeepr\Category\CategoryManager; -use de\RaumZeitLabor\PartKeepr\Category\CategoryManagerService; +use de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager; +use de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManagerService; use de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo; use de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer; @@ -97,6 +105,85 @@ PartKeepr::getEM()->flush(); echo "Creating footprints from SetupData/footprints.php\n"; +/* Import pre-defined footprints */ +$data = \Symfony\Component\Yaml\Yaml::load("../setup/data/footprints/footprints.yaml"); + +print_r($data); + +$footprintCategoryManager = FootprintCategoryManager::getInstance(); +$footprintCategoryManager->ensureRootExists(); + +function addFootprintPath (Array $path, $node) { + if (count($path) == 0) { return $node; } + $name = array_shift($path); + echo "Name is: ".$name."\n"; + + $childNode = null; + + foreach ($node->getChildren() as $child) { + if ($child->getNode()->getName() == $name) { + $childNode = $child; + } + } + + if ($childNode === null) { + $category = new FootprintCategory(); + $category->setParent($node->getNode()->getId()); + $category->setName($name); + $childNode = FootprintCategoryManager::getInstance()->addCategory($category); + } + + return addFootprintPath($path, $childNode); + +} + +foreach ($data as $footprintName => $footprintData) { + $footprint = new Footprint(); + $footprint->setName($footprintName); + + if (array_key_exists("description", $footprintData)) { + $footprint->setDescription($footprintData["description"]); + } + + if (array_key_exists("category", $footprintData)) { + // @todo add category + $footprintCategory = addFootprintPath(explode("/", $footprintData["category"]), $footprintCategoryManager->getRootNode()); + $footprint->setCategory($footprintCategory->getNode()); + } + + if (array_key_exists("image", $footprintData)) { + $footprintImage = new FootprintImage(); + $footprintImage->setFootprint($footprint); + $footprintImage->replace("../setup/data/footprints/" . $footprintData["image"]); + + $footprint->setImage($footprintImage); + } + + if (array_key_exists("attachments", $footprintData) && is_array($footprintData["attachments"])) { + foreach ($footprintData["attachments"] as $attachment) { + if (!is_array($attachment)) { + echo $footprintName ." has a string attachment\n"; + } + if (array_key_exists("url", $attachment)) { + $footprintAttachment = new FootprintAttachment(); + $footprintAttachment->setFootprint($footprint); + $footprintAttachment->replaceFromURL($attachment["url"]); + + if (array_key_exists("description", $attachment)) { + $footprintAttachment->setDescription($attachment["description"]); + } + + $footprint->getAttachments()->add($footprintAttachment); + } + + } + } + + PartKeepr::getEM()->persist($footprint); +} + +PartKeepr::getEM()->flush(); + $r = mysql_query("SELECT * FROM footprints"); while ($sFootprint = mysql_fetch_assoc($r)) { @@ -111,7 +198,7 @@ while ($sFootprint = mysql_fetch_assoc($r)) { echo "\n\Creating categories from existing data\n"; -$categoryManager = CategoryManager::getInstance(); +$categoryManager = PartCategoryManager::getInstance(); $categoryManager->ensureRootExists(); /* Pass 1: Create numeric nodes */ @@ -132,11 +219,12 @@ function addCategoryRecursive ($aCategories, $currentId, $parent) { foreach ($aCategories as $aCategory) { if ($aCategory["parentnode"] == $currentId) { echo "Adding ".sprintf("%40s", $aCategory["name"])."\r"; - $oCategory = new Category(); + $oCategory = new PartCategory(); $oCategory->setName(convertText($aCategory["name"])); $oCategory->setDescription(""); $oCategory->setParent($parent->getId()); - $category = CategoryManager::getInstance()->addCategory($oCategory); + + $category = PartCategoryManager::getInstance()->addCategory($oCategory); addCategoryRecursive($aCategories, $aCategory["id"], $category); diff --git a/util/classes/ExtJSFile.php b/util/classes/ExtJSFile.php @@ -138,7 +138,7 @@ class ExtJSFile { $aData = array($this->getJSBEntry()); foreach ($this->childs as $child) { - $aData[] = $child->getJSBEntry(); + $aData[] = $child->getJSB(); } return implode(",\n", $aData);