partkeepr

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

commit 3a6c57a3d1c6fd0b770b4e3211db83b20e4d1904
parent 3e94b3474c95aa174e5910d8f277d9ae42938960
Author: Felicitus <felicitus@felicitus.org>
Date:   Mon, 18 Mar 2013 15:36:02 +0100

Merge branch 'master' of github.com:partkeepr/PartKeepr

Diffstat:
Msrc/backend/PartKeepr/EventNotification/Event.php | 8++++++++
Msrc/backend/PartKeepr/Image/CachedImage.php | 2+-
Msrc/backend/PartKeepr/PartKeepr.php | 11+++++++++--
Msrc/backend/PartKeepr/Printing/Exceptions/InvalidArgumentException.php | 4++++
Msrc/backend/PartKeepr/Printing/Exceptions/RendererNotFoundException.php | 3+++
Msrc/backend/PartKeepr/Printing/PageBasicLayout/PageBasicLayout.php | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/backend/PartKeepr/Printing/PrintingJob/PrintingJob.php | 39+++++++++++++++++++++++++++++++++++++++
Msrc/backend/PartKeepr/Printing/PrintingJob/PrintingJobManager.php | 19+++++++++++++++++++
Msrc/backend/PartKeepr/Printing/PrintingJob/PrintingJobService.php | 19+++++++++++++++++++
Msrc/backend/PartKeepr/Printing/PrintingJobConfiguration/PrintingJobConfiguration.php | 52++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/backend/PartKeepr/Printing/PrintingJobConfiguration/PrintingJobConfigurationManager.php | 24++++++++++++++++++++++++
Msrc/backend/PartKeepr/Printing/PrintingJobConfiguration/PrintingJobConfigurationService.php | 19+++++++++++++++++++
Dsrc/backend/PartKeepr/Printing/Renderer/PDFDefaultRenderer.php | 279-------------------------------------------------------------------------------
Dsrc/backend/PartKeepr/Printing/Renderer/TCPDFAbstractRenderer.php | 190-------------------------------------------------------------------------------
Dsrc/backend/PartKeepr/Printing/Renderer/ZebraLabelWriterRenderer.php | 134-------------------------------------------------------------------------------
Msrc/backend/PartKeepr/Printing/RendererFactoryIfc.php | 6++++--
Msrc/backend/PartKeepr/Printing/RendererFactoryRegistry.php | 46++++++++++++++++++++++++++++++++++++++--------
Msrc/backend/PartKeepr/Printing/RendererIfc.php | 3+++
Msrc/backend/PartKeepr/Printing/SimpleRendererFactory.php | 46++++++++++++++++++++++++++++++++++++++++++++++
Msrc/backend/PartKeepr/Printing/Utils/DecodeConfiguration.php | 1+
Msrc/backend/PartKeepr/Printing/Utils/Placeholder.php | 47++++++++++++++++++++++++++++++++++++++++++-----
Asrc/backend/Plugins/PrintingRenderer/PDFDefaultRenderer/PDFDefaultRenderer.php | 233+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/Plugins/PrintingRenderer/PDFDefaultRenderer/TCPDFAbstractRenderer.php | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/Plugins/PrintingRenderer/ZebraLabelWriterRenderer/ZebraLabelWriterRenderer.php | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/frontend/js/Components/Part/Editor/PartEditorWindow.js | 49++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/frontend/js/Components/Printing/PrintingWindow.js | 23++++++++++++++++++-----
Msrc/frontend/js/Components/Widgets/DistributorComboBox.js | 21+--------------------
Msrc/frontend/js/Components/Widgets/FootprintComboBox.js | 20+-------------------
Msrc/frontend/js/Components/Widgets/ManufacturerComboBox.js | 21+--------------------
Msrc/frontend/js/Components/Widgets/PartUnitComboBox.js | 21+--------------------
Asrc/frontend/js/Components/Widgets/ReloadableComboBox.js | 23+++++++++++++++++++++++
Msrc/frontend/js/Components/Widgets/UnitComboBox.js | 21+--------------------
Msrc/frontend/js/Components/Widgets/UserComboBox.js | 21+--------------------
33 files changed, 1112 insertions(+), 753 deletions(-)

diff --git a/src/backend/PartKeepr/EventNotification/Event.php b/src/backend/PartKeepr/EventNotification/Event.php @@ -35,10 +35,18 @@ class Event extends BaseEntity{ $this->lastOccured = new \DateTime("now"); } + /** + * Sets the event name. + * @param unknown $name + */ public function setName( $name ){ $this->name = $name; } + /** + * Retrieves the event name. + * @return string + */ public function getName(){ return $this->name; } diff --git a/src/backend/PartKeepr/Image/CachedImage.php b/src/backend/PartKeepr/Image/CachedImage.php @@ -4,7 +4,7 @@ namespace PartKeepr\Image; use PartKeepr\PartKeepr; /** - * Represtends a cached image. Cached images are used for scale/resize + * Represents a cached image. Cached images are used for scale/resize * operations, so that the resize/scale operation doesn't need to be done * every time a scaled/resized image is requested. * diff --git a/src/backend/PartKeepr/PartKeepr.php b/src/backend/PartKeepr/PartKeepr.php @@ -318,12 +318,15 @@ class PartKeepr { return array( 'PartKeepr\User\User', 'PartKeepr\Session\Session', - + + 'PartKeepr\EventNotification\Event', + 'PartKeepr\EventNotification\LastNotification', + 'PartKeepr\Footprint\Footprint', 'PartKeepr\Footprint\FootprintImage', 'PartKeepr\Footprint\FootprintAttachment', 'PartKeepr\FootprintCategory\FootprintCategory', - + 'PartKeepr\Part\Part', 'PartKeepr\Part\PartUnit', 'PartKeepr\Part\PartManufacturer', @@ -331,6 +334,10 @@ class PartKeepr { 'PartKeepr\Part\PartImage', 'PartKeepr\Part\PartAttachment', 'PartKeepr\PartCategory\PartCategory', + + 'PartKeepr\Printing\PageBasicLayout\PageBasicLayout', + 'PartKeepr\Printing\PrintingJob\PrintingJob', + 'PartKeepr\Printing\PrintingJobConfiguration\PrintingJobConfiguration', 'PartKeepr\Project\Project', 'PartKeepr\Project\ProjectPart', diff --git a/src/backend/PartKeepr/Printing/Exceptions/InvalidArgumentException.php b/src/backend/PartKeepr/Printing/Exceptions/InvalidArgumentException.php @@ -3,6 +3,10 @@ namespace PartKeepr\Printing\Exceptions; use PartKeepr\Util\SerializableException; +/** + * Illeagal argument Expression. + * Will be thrown to indicate an error which was caused by invalid arguments. + */ class InvalidArgumentException extends SerializableException { public function __construct ($detailedReason) { parent::__construct( $detailedReason ); diff --git a/src/backend/PartKeepr/Printing/Exceptions/RendererNotFoundException.php b/src/backend/PartKeepr/Printing/Exceptions/RendererNotFoundException.php @@ -4,6 +4,9 @@ namespace PartKeepr\Printing\Exceptions; use PartKeepr\Util\SerializableException, PartKeepr\PartKeepr; +/** + * Expression will be thrown if a requested renderer was not found. + */ class RendererNotFoundException extends SerializableException { public function __construct ($detailedReason, $requestedClass, $availableClasses) { parent::__construct(PartKeepr::i18n("No adequate renderer found: $detailedReason \nRequested: $requestedClass \nAvailable: ".implode(", ",$availableClasses))); diff --git a/src/backend/PartKeepr/Printing/PageBasicLayout/PageBasicLayout.php b/src/backend/PartKeepr/Printing/PageBasicLayout/PageBasicLayout.php @@ -89,86 +89,170 @@ class PageBasicLayout extends BaseEntity implements Serializable, Deserializable */ private $topLeftYInMM = 0; + /** + * Sets name. + * @param string $name + */ public function setName( $name ){ $this->name = $name; } + /** + * Retrives name. + * @return string + */ public function getName(){ return $this->name; } + /** + * Sets the comment. + * @param unknown $comment + */ public function setComment( $comment ){ $this->comment = $comment; } + /** + * Retrieve comment. + * @return unknown + */ public function getComment(){ return $this->comment; } + /** + * Sets column count. + * @param unknown $count + */ public function setColumnCount( $count ){ $this->columnCount = $count; } + /** + * Retrieve column count. + * @return number + */ public function getColumnCount(){ return $this->columnCount; } + /** + * Sets row count. + * @param unknown $count + */ public function setRowCount( $count ){ $this->rowCount = $count; } + /** + * Retrieve row count. + * @return number + */ public function getRowCount(){ return $this->rowCount; } + /** + * Sets paper size + * @param unknown $size + */ public function setPaperSize( $size ){ $this->paperSize = $size; } + /** + * Retrieve paper size. + * @return string + */ public function getPaperSize(){ return $this->paperSize; } + /** + * Sets Paper portrait. + * @param unknown $portrait + */ public function setPaperPortrait( $portrait ){ $this->paperPortrait = $portrait; } + /** + * Retrieves paper portrait. + * @return boolean + */ public function getPaperPortrait(){ return $this->paperPortrait; } + /** + * Sets cell width in mm + * @param unknown $size + */ public function setCellWidthInMM( $size ){ $this->cellWidthInMM = $size; } + /** + * Retrieves cell width in mm. + * @return number + */ public function getCellWidthInMM( ){ return $this->cellWidthInMM; } + /** + * Sets cell height in mm + * @param unknown $size + */ public function setCellHeightInMM( $size ){ $this->cellHeightInMM = $size; } + /** + * retrieves cell height in mm. + * @return number + */ public function getCellHeightInMM( ){ return $this->cellHeightInMM; } + /** + * Sets top left position x in mm. + * @param unknown $pos + */ public function setTopLeftXInMM( $pos ){ $this->topLeftXInMM = $pos; } + /** + * Gets top left position x in mm. + * @return number + */ public function getTopLeftXInMM(){ return $this->topLeftXInMM; } + /** + * Sets top left position y in mm. + * @param unknown $pos + */ public function setTopLeftYInMM( $pos ){ $this->topLeftYInMM = $pos; } - + + /** + * Retrieves top left y position in mm. + * @return number + */ public function getTopLeftYInMM(){ return $this->topLeftYInMM; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Util\Serializable::serialize() + */ public function serialize () { return array( "id" => $this->getId(), @@ -185,6 +269,10 @@ class PageBasicLayout extends BaseEntity implements Serializable, Deserializable ); } + /** + * (non-PHPdoc) + * @see \PartKeepr\Util\Deserializable::deserialize() + */ public function deserialize (array $parameters) { foreach ($parameters as $key => $value) { switch ($key) { diff --git a/src/backend/PartKeepr/Printing/PrintingJob/PrintingJob.php b/src/backend/PartKeepr/Printing/PrintingJob/PrintingJob.php @@ -64,42 +64,81 @@ class PrintingJob extends BaseEntity implements Serializable { } } + /** + * Retrieve created field. + */ public function getCreated(){ return $this->created; } + /** + * Sets done to new value. + * @param boolean $done + */ public function setDone( $done ){ $this->done = $done; } + /** + * Retrieve done field. + * @return boolean + */ public function getDone(){ return $this->done; } + /** + * Sets data field to a file. + * @param TempUploadedFile $data + */ public function setData( TempUploadedFile $data ){ $this->data = $data; } + /** + * Retrieve data file. + * @return TempUploadedFile + */ public function getData( ){ return $this->data; } + /** + * Sets the owner of this job. + * @param User $user + */ public function setOwner( User $user ) { $this->owner = $user; } + /** + * Retrieves owner of this job. + * @return User + */ public function getOwner() { return $this->owner; } + /** + * Sets the target of this job. + * @param User $user + */ public function setTarget( User $user ){ $this->target = $user; } + /** + * Retrieve target for this job. + * @return User + */ public function getTarget() { return $this->target; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Util\Serializable::serialize() + */ public function serialize () { return array( "id" => $this->getId(), diff --git a/src/backend/PartKeepr/Printing/PrintingJob/PrintingJobManager.php b/src/backend/PartKeepr/Printing/PrintingJob/PrintingJobManager.php @@ -10,19 +10,38 @@ use Doctrine\ORM\Query, PartKeepr\Util\Singleton, PartKeepr\Util\Exceptions\ObjectNotFoundException; +/** + * The manager for the PrintingJob. + */ class PrintingJobManager extends AbstractManager { + /** + * (non-PHPdoc) + * @see \PartKeepr\Manager\AbstractManager::getEntityName() + */ public function getEntityName () { return 'PartKeepr\Printing\PrintingJob\PrintingJob'; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Manager\AbstractManager::getQueryFields() + */ public function getQueryFields () { return array("id","created","done","ow.id AS owner","ta.id AS target","da.id AS data"); } + /** + * (non-PHPdoc) + * @see \PartKeepr\Manager\AbstractManager::getDefaultSortField() + */ public function getDefaultSortField () { return "created"; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Manager\AbstractManager::applyCustomQuery() + */ protected function applyCustomQuery (QueryBuilder $qb, ManagerFilter $filter) { /** * Pull in additional tables diff --git a/src/backend/PartKeepr/Printing/PrintingJob/PrintingJobService.php b/src/backend/PartKeepr/Printing/PrintingJob/PrintingJobService.php @@ -10,6 +10,9 @@ use PartKeepr\PartKeepr, PartKeepr\Service\Service, PartKeepr\Session\SessionManager; +/** + * This is the exposed restful service for working with the PrintingJobs. + */ class PrintingJobService extends Service implements RestfulService { /** * Checks the permission and throws an exception if the access is denied. @@ -21,6 +24,10 @@ class PrintingJobService extends Service implements RestfulService { throw new \Exception("Permission denied!"); } + /** + * (non-PHPdoc) + * @see \PartKeepr\Service\RestfulService::get() + */ public function get () { if ($this->hasParameter("id")) { $job = PrintingJobManager::getInstance()->getEntity($this->getParameter("id")); @@ -34,6 +41,10 @@ class PrintingJobService extends Service implements RestfulService { } } + /** + * + * @param unknown $queryBuilder + */ public function filterCallback ($queryBuilder) { $filter = new FilterExtractor($this); @@ -50,6 +61,10 @@ class PrintingJobService extends Service implements RestfulService { } } + /** + * (non-PHPdoc) + * @see \PartKeepr\Service\RestfulService::create() + */ public function create () { throw new \Exception("Creation of printing jobs cannot be done by this service!"); } @@ -71,6 +86,10 @@ class PrintingJobService extends Service implements RestfulService { return array("data" => $obj->serialize()); } + /** + * (non-PHPdoc) + * @see \PartKeepr\Service\RestfulService::destroy() + */ public function destroy () { $this->requireParameter("id"); $id = $this->getParameter("id"); diff --git a/src/backend/PartKeepr/Printing/PrintingJobConfiguration/PrintingJobConfiguration.php b/src/backend/PartKeepr/Printing/PrintingJobConfiguration/PrintingJobConfiguration.php @@ -54,54 +54,94 @@ class PrintingJobConfiguration extends BaseEntity implements Serializable, Deser */ private $rendererConfiguration; + /** + * Sets the name. + */ public function setName( $name ){ $this->name = $name; } + /** + * Retrieves the name + */ public function getName(){ return $this->name; } + /** + * Sets comment. + */ public function setComment( $comment ){ $this->comment = $comment; } - + + /** + * Rerieve comment. + */ public function getComment(){ return $this->comment; } + /** + * Sets object type. + */ public function setObjectType( $type ){ $this->objectType = $type; } - + + /** + * Retrieve object type. + */ public function getObjectType( ){ return $this->objectType; } + /** + * Sets the export renderer to use for this job. + */ public function setExportRenderer( $rendererName ){ $this->exportRenderer = $rendererName; } - + + /** + * Retrieve the export renderer. + */ public function getExportRenderer(){ return $this->exportRenderer; } + /** + * Sets the page layout. + */ public function setPageLayout( $layout ){ $this->pageLayout = $layout; } - + + /** + * Retrieves page layout. + */ public function getPageLayout(){ return $this->pageLayout; } + /** + * Set render configuration. + */ public function setRendererConfiguration( $cfg ){ $this->rendererConfiguration = $cfg; } + /** + * Retrieve render configuration. + */ public function getRendererConfiguration(){ return $this->rendererConfiguration; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Util\Serializable::serialize() + */ public function serialize () { return array( "id" => $this->getId(), @@ -114,6 +154,10 @@ class PrintingJobConfiguration extends BaseEntity implements Serializable, Deser ); } + /** + * (non-PHPdoc) + * @see \PartKeepr\Util\Deserializable::deserialize() + */ public function deserialize (array $parameters) { foreach ($parameters as $key => $value) { switch ($key) { diff --git a/src/backend/PartKeepr/Printing/PrintingJobConfiguration/PrintingJobConfigurationManager.php b/src/backend/PartKeepr/Printing/PrintingJobConfiguration/PrintingJobConfigurationManager.php @@ -7,19 +7,38 @@ use PartKeepr\Manager\AbstractManager, PartKeepr\Util\Singleton, PartKeepr\Util\Exceptions\ObjectNotFoundException; +/** + * This is the manager for our printing job configurations. + */ class PrintingJobConfigurationManager extends AbstractManager { + /** + * (non-PHPdoc) + * @see \PartKeepr\Manager\AbstractManager::getEntityName() + */ public function getEntityName () { return 'PartKeepr\Printing\PrintingJobConfiguration\PrintingJobConfiguration'; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Manager\AbstractManager::getQueryFields() + */ public function getQueryFields () { return array("id", "name", "comment", "objectType", "exportRenderer", "rendererConfiguration"); } + /** + * (non-PHPdoc) + * @see \PartKeepr\Manager\AbstractManager::getDefaultSortField() + */ public function getDefaultSortField () { return "name"; } + /** + * Removes a configuration with the given id from the database. + * @param unknown $id + */ public function deleteConfiguration ($id) { $part = PartManager::getInstance()->getConfiguration($id); @@ -27,6 +46,11 @@ class PrintingJobConfigurationManager extends AbstractManager { PartKeepr::getEM()->flush(); } + /** + * Get configuration by its id. + * @param unknown $id + * @return unknown + */ public function getConfiguration ($id) { $part = PartKeepr::getEM()->find(getEntityName(), $id); diff --git a/src/backend/PartKeepr/Printing/PrintingJobConfiguration/PrintingJobConfigurationService.php b/src/backend/PartKeepr/Printing/PrintingJobConfiguration/PrintingJobConfigurationService.php @@ -9,7 +9,14 @@ use PartKeepr\PartKeepr, PartKeepr\Service\FilterExtractor, PartKeepr\Service\Service; +/** + * This is our restful service to work with the printing job configurations. + */ class PrintingJobConfigurationService extends Service implements RestfulService { + /** + * (non-PHPdoc) + * @see \PartKeepr\Service\RestfulService::get() + */ public function get () { if ($this->hasParameter("id")) { return array("data" => PrintingJobConfigurationManager::getInstance()->getEntity($this->getParameter("id"))->serialize()); @@ -34,6 +41,10 @@ class PrintingJobConfigurationService extends Service implements RestfulService } } + /** + * (non-PHPdoc) + * @see \PartKeepr\Service\RestfulService::create() + */ public function create () { $this->requireParameter("name"); @@ -46,6 +57,10 @@ class PrintingJobConfigurationService extends Service implements RestfulService return array("data" => $obj->serialize()); } + /** + * (non-PHPdoc) + * @see \PartKeepr\Service\RestfulService::update() + */ public function update () { $this->requireParameter("id"); $this->requireParameter("name"); @@ -58,6 +73,10 @@ class PrintingJobConfigurationService extends Service implements RestfulService } + /** + * (non-PHPdoc) + * @see \PartKeepr\Service\RestfulService::destroy() + */ public function destroy () { $this->requireParameter("id"); diff --git a/src/backend/PartKeepr/Printing/Renderer/PDFDefaultRenderer.php b/src/backend/PartKeepr/Printing/Renderer/PDFDefaultRenderer.php @@ -1,279 +0,0 @@ -<?php -namespace PartKeepr\Printing\Renderer; - -use PartKeepr\Part\Part, - PartKeepr\Printing\Exceptions\RendererNotFoundException, - PartKeepr\Printing\PageBasicLayout\PageBasicLayout, - PartKeepr\Printing\RendererFactoryRegistry, - PartKeepr\Printing\Renderer\TCPDFAbstractRenderer, - PartKeepr\Printing\SimpleRendererFactory, - PartKeepr\Printing\Utils\PercentOrNumericHelper, - PartKeepr\Printing\Utils\Placeholder, - PartKeepr\Printing\Utils\DecodeConfiguration, - PartKeepr\StorageLocation\StorageLocation - ; - -/** - * This class implements a way to render different datasets to - * a labeling layout. - */ -class PDFDefaultRenderer extends TCPDFAbstractRenderer{ - /** - * Our default configuration for this label renderer. - * @var array - */ - private $defaultConfiguration = array( - 'barcodeEnable' => false, - 'barcodeType' => 'QRCODE,L', - 'textBarcode' => "PA/!!id!!", - 'barcodeWidth' => "12", - 'barcodeHeight' => "12", - 'barcodeXPos' => "-7", - 'barcodeYPos' => "-7", - 'barcodeWithText' => false, - 'barcode2D' => true, - 'fontFamily' => 'times', - 'fontStyle' => '', - 'fontSize' => 12, - 'text' => '<span style="font-size: 11pt;"><b>!!name!!</b></span><br><span style="font-size: 8pt;">!!description!!</span>' - ); - - public function __construct (array $objects, $cfgString ) { - $configuration = DecodeConfiguration::decode($cfgString); - - // Apply the personal default configuration here. - // The base will apply the base default parameters for you. - $configuration = array_merge( $this->defaultConfiguration, $configuration ); - parent::__construct( $objects, $configuration); - } - - public function passRenderingData( $data ){ - // Here we got our data passed. We have to decide how we want - // to render the data, so we dispatch it to our internal rendering - // methods to make the code more clear. - if ( is_array( $data ) ){ - if (count($data)>0){ - $elem = reset($data); - if ($elem instanceof StorageLocation){ - $this->renderStorageLocations($data); - } elseif ($elem instanceof Part){ - $this->renderParts($data); - } - else{ - throw new RendererNotFoundException("Unable to handle object type with renderer PDFLabelRenderer.", - get_class($elem),array("StorageLocation")); - } - } - } - else{ - // If the selected object is not an array, we make an array first - // to have only one case to handle. - passRenderingData( array( $ata ) ); - } - } - - /** - * This method renders an array of StorageLocations to our sheet. - * @param array $locations - */ - private function renderStorageLocations( array $locations ){ - foreach ($locations as $location){ - $this->renderCellFromLocation( $location ); - } - } - - /** - * This method just renders the next single cell with the given location - * as content. - */ - private function renderCellFromLocation( StorageLocation $location ){ - // Move the pointer to the next cell and initialize PDF class - // correctly. Also draws the grid if necessary. - $this->initNextCell(); - - $padding = 3; - - $name = $location->getName(); - - $this->pdf->SetCellPadding($padding); - $this->pdf->SetFont( $this->configuration['fontFamily'], - $this->configuration['fontStyle'], - $this->configuration['fontSize']); - $this->pdf->SetXY( $this->xCellPos,$this->yCellPos ); - - // Start clipping. Every thing with StartTransform and StopTransform - // will be clipped to the Rect. This is a cool feature if one field is - // too long, it will not destroy the rest of your page and it is partial - // usable. - $this->pdf->StartTransform(); - // Draw clipping rectangle to match html cell. - $this->pdf->Rect($this->xCellPos, $this->yCellPos, $this->layout->getCellWidthInMM(), - $this->layout->getCellHeightInMM(), 'CNZ'); - - $this->pdf->MultiCell( $this->layout->getCellWidthInMM(), - $this->layout->getCellHeightInMM(), $name, '0'); - - $this->pdf->StopTransform(); - - // Place a Barcode at the end - if ($this->configuration['barcodeEnable']){ - $barcodeWidth = $this->configuration['barcodeWidth']; - $barcodeHeight = $this->layout->getCellHeightInMM() - 5; - - if ($this->configuration['barcode2D']){ - $this->pdf->write2DBarcode($name, $this->configuration['barcodeType'], - $this->xCellPos + $this->layout->getCellWidthInMM() - $barcodeWidth - 5, - $this->yCellPos + $this->layout->getCellHeightInMM() / 2 - $barcodeHeight / 2, - $barcodeWidth, - $barcodeHeight - ); - } - else { - $style = array('text'=> $this->configuration['barcodeWithText'] ); - $this->pdf->write1DBarcode($name, $this->configuration['barcodeType'], - $this->xCellPos + $this->layout->getCellWidthInMM() - $barcodeWidth - 5, - $this->yCellPos + $this->layout->getCellHeightInMM() / 2 - $barcodeHeight / 2, - $barcodeWidth, - $barcodeHeight, - "", - $style - ); - } - } - } - - /** - * This method renders an array of Parts to our sheet. - * @param array $parts - */ - private function renderParts( array $parts ){ - foreach ($parts as $part){ - $this->renderCellFromPart( $part ); - } - } - - /** - * This method just renders the next single cell with a part - * as content. - */ - private function renderCellFromPart( Part $part ){ - // Move the pointer to the next cell and initialize PDF class - // correctly. Also draws the grid if necessary. - $this->initNextCell(); - - $padding = 3; - - $dataReplacement = new Placeholder( $part, "!!", "!!" ); - - $text = $dataReplacement->apply($this->configuration['text']); - $barcodeId = $dataReplacement->apply($this->configuration['textBarcode'] ); - - $this->pdf->SetCellPadding($padding); - $this->pdf->SetFont( $this->configuration['fontFamily'], - $this->configuration['fontStyle'], - $this->configuration['fontSize']); - $this->pdf->SetXY( $this->xCellPos,$this->yCellPos ); - - if ($this->configuration['barcodeEnable']){ - $widthParameter = new PercentOrNumericHelper($this->configuration['barcodeWidth']); - $heightParameter = new PercentOrNumericHelper($this->configuration['barcodeHeight']); - $xPosParameter = new PercentOrNumericHelper($this->configuration['barcodeXPos']); - $yPosParameter = new PercentOrNumericHelper($this->configuration['barcodeYPos']); - - $xPos = $xPosParameter->getValueWrap(0, $this->layout->getCellWidthInMM() ); - $yPos = $yPosParameter->getValueWrap(0, $this->layout->getCellHeightInMM() ); - $width = $widthParameter->getValue(0,$this->layout->getCellWidthInMM()); - $height = $heightParameter->getValue(0,$this->layout->getCellHeightInMM()); - - $regions = array(); - - $this->pdf->resetInternalMargins(); - - if ($this->configuration['barcode2D']){ - $this->pdf->write2DBarcode($barcodeId, $this->configuration['barcodeType'], - $this->xCellPos + $xPos - $width / 2 , - $this->yCellPos + $yPos - $height / 2, - $width, - $height - ); - } - - // This region will add a "do not write text here" over our barcode This is a kind - // of hack to make text fluently moving around :) - $textMarginX = 7; - $textMarginY = 7; - - $left = $xPos < $this->layout->getCellWidthInMM() / 2; - $top = $yPos < $this->layout->getCellHeightInMM() / 2; - - // $this->pdf->writeHTML("LEFT: $left TOP: $top XPOS: $xPos YPOS: $yPos WIDTH: ".$this->layout->getCellWidthInMM()." HEIGHT: ".$this->layout->getCellHeightInMM(), true, false, true, false, ''); - if( $left ) - { - if( $top ){ - $regions[] = array('page' => '' - , 'xt' => $xPos + $this->xCellPos + $textMarginX - , 'yt' => 0 - , 'xb' => $xPos + $this->xCellPos + $textMarginX - , 'yb' => $yPos + $this->yCellPos + $textMarginY, 'side' => 'L'); - }else - { - $regions[] = array('page' => '' - , 'xt' => $xPos + $this->xCellPos + $textMarginX - , 'yt' => $yPos + $this->yCellPos - $textMarginY - , 'xb' => $xPos + $this->xCellPos + $textMarginX - , 'yb' => $this->yCellPos + $this->layout->getCellHeightInMM() - , 'side' => 'L'); - } - }else - { - if( $top ){ - $regions[] = array('page' => '' - , 'xt' => $xPos + $this->xCellPos - $textMarginX - , 'yt' => 0 - , 'xb' => $xPos + $this->xCellPos - $textMarginX - , 'yb' => $yPos + $this->yCellPos + $textMarginY, 'side' => 'R'); - }else - { - $regions[] = array('page' => '' - , 'xt' => $xPos + $this->xCellPos - $width / 2 - $textMarginX - , 'yt' => $yPos + $this->yCellPos - $height/ 2 - $textMarginY - , 'xb' => $xPos + $this->xCellPos - $width / 2 - $textMarginX - , 'yb' => $this->yCellPos + $this->layout->getCellHeightInMM() - , 'side' => 'R'); - } - } - $this->pdf->setPageRegions($regions); - } - - // Start clipping. Every thing with StartTransform and StopTransform - // will be clipped to the Rect. This is a cool feature if one field is - // too long, it will not destroy the rest of your page and it is partial - // usable. - $this->pdf->StartTransform(); - // Draw clipping rectangle to match html cell. - $this->pdf->Rect($this->xCellPos, $this->yCellPos, $this->layout->getCellWidthInMM(), - $this->layout->getCellHeightInMM(), 'CNZ'); - - $this->pdf->WriteHTMLCell( $this->layout->getCellWidthInMM(), - $this->layout->getCellHeightInMM(), - $this->xCellPos, - $this->yCellPos, - $text); - - $this->pdf->StopTransform(); - - $this->pdf->setPageRegions(); - } -} - -// We have to register this class to the registry. -// Only if the class is registered, it can be found by the -// registry and you will see it in the application. -RendererFactoryRegistry::getInstance()->registerFactory( - new SimpleRendererFactory("Default PDF renderer", - "PartKeepr\Printing\Renderer\PDFDefaultRenderer", - array("PartKeepr\StorageLocation\StorageLocation", - "PartKeepr\Part\Part"), - array("PartKeepr\Printing\PageBasicLayout\PageBasicLayout") - ) - ); diff --git a/src/backend/PartKeepr/Printing/Renderer/TCPDFAbstractRenderer.php b/src/backend/PartKeepr/Printing/Renderer/TCPDFAbstractRenderer.php @@ -1,190 +0,0 @@ -<?php -namespace PartKeepr\Printing\Renderer; - -use PartKeepr\Printing\RendererIfc, - PartKeepr\Printing\RendererFactoryRegistry, - PartKeepr\Printing\RendererNotFoundException, - PartKeepr\Printing\SimpleRendererFactory, - PartKeepr\Printing\PageBasicLayout\PageBasicLayout, - PartKeepr\StorageLocation\StorageLocation - ; - -require_once('tcpdf/tcpdf.php'); - -/** - * This wrapper class can be used to remove some bugs from the - * TCPDF. https://sourceforge.net/p/tcpdf/bugs/773/ - * @author sven - * - */ -class TCPDFWrapper extends \TCPDF{ - public function __construct($orientation, $unit, $format){ - parent::__construct($orientation, $unit, $format); - } - - public function resetInternalMargins(){ - $this->crMargin = $this->rMargin = $this->original_rMargin; - $this->clMargin = $this->lMargin = $this->original_lMargin; - } -} - -/** - * This class is a abstract renderer to help somebody by creating its - * own plugins. Use the PDFDefaultRenderer as an example. - */ -abstract class TCPDFAbstractRenderer implements RendererIfc{ - /** - * This contains our layout for the page to be rendered. - */ - protected $layout = null; - - /** - * Our internal used pdf generator. - */ - protected $pdf; - - /** - * This is the count of the cells we have actually rendered. You can name - * it a pointer to the next cell, which should be rendered. We render all - * columns first and then increment the row. - */ - protected $cellsRendered; - - /** - * This is the position of the actual cell we want to process. - * Top left point. - */ - protected $xCellPos = 0; - - /** - * This is the position of the actual cell we want to process. - * Top left point. - */ - protected $yCellPos = 0; - - /** - * This is an array with configuration things. - * @var array - */ - protected $configuration; - - /** - * This boolean can be set to true to not trigger an error on startup. - * We implement it this way, to ensure the implementer of the plugin has - * thought of this potential security risk. - * - * @var unknown - */ - protected $doNotErrorIfTCPDFSetsCalls = false; - - /** - * Our default configuration for this label renderer. - * @var array - */ - protected $basedefaultConfiguration = array( - 'borderGrid' => true, - 'startingCell' => 0 - ); - - public function __construct ( array $objects, array $configuration ) { - foreach( $objects as $obj ){ - if ($obj instanceof \PartKeepr\Printing\PageBasicLayout\PageBasicLayout){ - $this->layout = $obj; - } - } - - if ($this->layout === null){ - throw new \PartKeepr\Printing\Exceptions\InvalidArgumentException("Required object not passed!"); - } - - $this->configuration = array_merge( $this->basedefaultConfiguration, $configuration ); - - $this->cellsRendered = $this->configuration['startingCell']; - - if (K_TCPDF_CALLS_IN_HTML && !$doNotErrorIfTCPDFSetsCalls){ - trigger_error("TCPDF has set K_TCPDF_CALLS_IN_HTML to true, which is a security issue with this class since the user can modify the html text!",E_USER_ERROR); - } - - $this->pdf = new TCPDFWrapper( $this->layout->getPaperPortrait() ? 'P': 'L' - , 'mm', $this->layout->getPaperSize() ); - - // set document information - $this->pdf->SetCreator(PDF_CREATOR); - $this->pdf->SetAuthor('PartDB'); - $this->pdf->SetTitle('PartDB Labeling Document'); - $this->pdf->SetSubject('This is a priontout of for labeling or indexing'); - $this->pdf->SetKeywords('PartDB'); - - // remove default header/footer - $this->pdf->setPrintHeader(false); - $this->pdf->setPrintFooter(false); - - // set default monospaced font - $this->pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); - - //set margins - $this->pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); - - //set auto page breaks - $this->pdf->SetAutoPageBreak(FALSE, PDF_MARGIN_BOTTOM); - - //set image scale factor - $this->pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); - - //set some language-dependent strings - //$this->pdf->setLanguageArray($l); - - // --------------------------------------------------------- - } - - public function getSuggestedExtension(){ - return "pdf"; - } - - public function storeResult( $outFile ){ - $this->pdf->Output($outFile, 'F'); - } - - public function outputResult($filename){ - $this->pdf->Output($filename, 'I'); - } - - protected function renderBorderGrid(){ - $colYStart = $this->layout->getTopLeftYInMM(); - $colYEnd = $this->layout->getRowCount() * $this->layout->getCellHeightInMM() + $this->layout->getTopLeftYInMM(); - - $rowXStart = $this->layout->getTopLeftXInMM(); - $rowXEnd = $this->layout->getColumnCount() * $this->layout->getCellWidthInMM() + $this->layout->getTopLeftXInMM(); - - for ($r=0; $r <= $this->layout->getRowCount(); $r++){ - $rowYPos = $r * $this->layout->getCellHeightInMM() + $this->layout->getTopLeftYInMM(); - $this->pdf->Line( $rowXStart, $rowYPos, $rowXEnd, $rowYPos ); - } - - for ($c=0; $c <= $this->layout->getColumnCount(); $c++){ - $colXPos = $c * $this->layout->getCellWidthInMM() + $this->layout->getTopLeftXInMM(); - $this->pdf->Line( $colXPos, $colYStart, $colXPos, $colYEnd ); - } - } - - /** - * Opens the cell and sets the class to the correct coordinates. - */ - protected function initNextCell(){ - $page = floor( $this->cellsRendered / ($this->layout->getColumnCount() * $this->layout->getRowCount())); - $cellXCoordinate = $this->cellsRendered % $this->layout->getColumnCount(); - $cellYCoordinate = ( floor($this->cellsRendered / $this->layout->getColumnCount()) ) % $this->layout->getRowCount() ; - - $this->xCellPos = $cellXCoordinate * $this->layout->getCellWidthInMM() + $this->layout->getTopLeftXInMM(); - $this->yCellPos = $cellYCoordinate * $this->layout->getCellHeightInMM() + $this->layout->getTopLeftYInMM(); - - if ($cellXCoordinate == 0 && $cellYCoordinate == 0){ - $this->pdf->AddPage(); - if ($this->configuration['borderGrid']){ - $this->renderBorderGrid(); - } - } - - $this->cellsRendered++; - } -} diff --git a/src/backend/PartKeepr/Printing/Renderer/ZebraLabelWriterRenderer.php b/src/backend/PartKeepr/Printing/Renderer/ZebraLabelWriterRenderer.php @@ -1,134 +0,0 @@ -<?php -namespace PartKeepr\Printing\Renderer; - -use PartKeepr\Part\Part, - PartKeepr\Printing\PageBasicLayout\PageBasicLayout, - PartKeepr\Printing\RendererFactoryRegistry, - PartKeepr\Printing\RendererIfc, - PartKeepr\Printing\SimpleRendererFactory, - PartKeepr\Printing\Exceptions\RendererNotFoundException, - PartKeepr\Printing\Utils\DecodeConfiguration, - PartKeepr\Printing\Utils\Placeholder, - PartKeepr\StorageLocation\StorageLocation - ; - -/** - * This class implements a printing renderer which renders the data - * to the ZPL printing language. The idea behind is to create a template using - * the Designer software provided by Zebra, print it to a file and then use this - * file as a template here. - */ -class ZebraLabelWriterRenderer implements RendererIfc{ - /** - * Our default configuration for this label renderer. - * @var array - */ - private $defaultConfiguration = array( - 'part' => array( 'template' => -<<<'EOD' -CT~~CD,~CC^~CT~ -^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA^PR3,3~SD8^JUS^LRN^CI0^XZ -^XA -^MMT -^PW320 -^LL0176 -^LS0 -^FT16,44^A0N,34,33^FH\^FD<<name>>^FS -^FT16,76^A0N,23,24^FH\^FD<<description>>^FS -^BY3,3,33^FT49,146^BCN,,Y,N -^FD>;<<id>>^FS -^PQ1,0,1,Y^XZ -EOD - ) - ); - - /** - * The rendered data up to now. - */ - protected $out = ""; - - /** - * This is the current active configuration. - * @var unknown - */ - protected $configuration; - - /** - * This is the configuration passed to this class. - * @var unknown - */ - protected $configurationIn; - - public function __construct (array $obj, $cfgString ) { - $configuration = DecodeConfiguration::decode($cfgString); - $this->configurationIn = $configuration; - } - - public function passRenderingData( $data ){ - // Here we got our data passed. We have to decide how we want - // to render the data, so we dispatch it to our internal rendering - // methods to make the code more clear. - if ( is_array( $data ) ){ - if (count($data)>0){ - $elem = reset($data); - if ($elem instanceof StorageLocation){ - $this->renderStorageLocations($data); - } elseif ($elem instanceof Part){ - $this->renderParts($data); - } - else{ - throw new RendererNotFoundException("Unable to handle object type with this renderer.", - get_class($elem),array("StorageLocation")); - } - } - } - else{ - // If the selected object is not an array, we make an array first - // to have only one case to handle. - passRenderingData( array( $ata ) ); - } - } - - /** - * This method renders an array of Parts to our sheet. - * @param array $parts - */ - private function renderParts( array $parts ){ - $this->configuration = array_merge( $this->defaultConfiguration['part'], $this->configurationIn ); - - foreach ($parts as $part){ - $this->renderSinglePart( $part ); - } - } - - - private function renderSinglePart( Part $part ){ - $dataReplacement = new Placeholder( $part, "<<", ">>"); - $this->out .= $dataReplacement->apply($this->configuration['template']) . "\n"; - } - - public function getSuggestedExtension(){ - return "zpl"; - } - - public function storeResult( $outFile ){ - $file = fopen($outFile,'w'); - fwrite( $file, $this->out ); - fclose( $file ); - } - - public function outputResult($filename){ - return $this->out; - } -} - -// We have to register this class to the registry. -// Only if the class is registered, it can be found by the -// registry and you will see it in the application. -RendererFactoryRegistry::getInstance()->registerFactory( - new SimpleRendererFactory("Zebra Label Renderer", - "PartKeepr\Printing\Renderer\ZebraLabelWriterRenderer", - array("PartKeepr\Part\Part"), - array() - ) - ); diff --git a/src/backend/PartKeepr/Printing/RendererFactoryIfc.php b/src/backend/PartKeepr/Printing/RendererFactoryIfc.php @@ -32,13 +32,15 @@ interface RendererFactoryIfc{ public function getCreatedClassname(); /** - * Retruns the supported classes which can be passed to the renderer + * Returns the supported classes which can be passed to the renderer * via passRenderingdata($data). */ public function getSupportedClassesForRendering(); /** - * Returns the object types, which are required for operation. + * Returns the object types, which are required for operation. They + * must be passed to the $configuration parameter as an array. + * * @return An array holding the names of the type instances needed. */ public function getParameterObjectTypes(); diff --git a/src/backend/PartKeepr/Printing/RendererFactoryRegistry.php b/src/backend/PartKeepr/Printing/RendererFactoryRegistry.php @@ -11,26 +11,35 @@ use PartKeepr\Util\Singleton, * and provide an interface to fetch them as needed. */ class RendererFactoryRegistry extends Singleton { + /** + * Our list of known factories. + * + * @var array of RendererFactoryIfc instances. + */ var $factories = array(); + /** + * Indicates wheather the renderer finding has been exectued so far. + * @var unknown + */ var $findRendererAlreadyRun = false; /** * Returns a renderer factory by its class name. * @param string className The name of the class to fetch the factory for. */ - public function getRendererFactory( $className ){ + public function getRendererFactory( $classNameWithNamespace ){ $this->findRenderer(); - if ($className===null){ + if ($classNameWithNamespace===null){ return $this->factories; } - if (!array_key_exists($className, $this->factories) ){ - throw new RendererNotFoundException("No renderer found in registry.",$className, array_keys($this->factories)); + if (!array_key_exists($classNameWithNamespace, $this->factories) ){ + throw new RendererNotFoundException("No renderer found in registry.",$classNameWithNamespace, array_keys($this->factories)); } - return $this->factories[ $className ]; + return $this->factories[ $classNameWithNamespace ]; } /** @@ -62,13 +71,34 @@ class RendererFactoryRegistry extends Singleton { /** * This method searches for the renderer in den Renderer directory and - * loads them. + * loads them. The class itself ensures to run this method once before + * the data from this run is needed. */ public function findRenderer(){ if (!$this->findRendererAlreadyRun){ - foreach (glob(dirname(__FILE__).DIRECTORY_SEPARATOR."Renderer".DIRECTORY_SEPARATOR."*.php") as $filename) { + foreach (glob(dirname(__FILE__).DIRECTORY_SEPARATOR."Renderer".DIRECTORY_SEPARATOR."*Renderer") as $filename) { + $filename = $filename . DIRECTORY_SEPARATOR . basename($filename) . ".php"; if (is_file($filename)) { - require_once($filename); + $className = basename($filename,'.php'); + $classNameWithNamespace = 'PartKeepr\\Printing\\Renderer\\'.$className.'\\'.$className; + $exists = class_exists($classNameWithNamespace); + if ( $exists ){ + try { + $onRegister = new \ReflectionMethod($classNameWithNamespace,'onRegister'); + if ($onRegister->isStatic()){ + // Enough sanity checks, if now something goes wrong, we will fail. + $onRegister->invoke(null,$this); + }else{ + trigger_error("Method onRegister in class $classNameWithNamespace is not static, ignoring class.",E_USER_WARNING ); + } + } catch( \ReflectionException $e) + { + trigger_error("Method onRegister in class $classNameWithNamespace gave an error: ".$e->getMessage().". Ignoring class.",E_USER_WARNING ); + } + }else{ + // Sanely ignore this case, because this may arise often if a needed library is not present. + // trigger_error("File $filename does not contain a class with $classNameWithNamespace.",E_USER_WARNING ); + } } } diff --git a/src/backend/PartKeepr/Printing/RendererIfc.php b/src/backend/PartKeepr/Printing/RendererIfc.php @@ -5,6 +5,9 @@ namespace PartKeepr\Printing; * The rendering interface is used to pass data to a renderer and * retrieve the rendered results afterwards. How the data is rendered * and which data can be processed is implementation specific. + * + * Add a static method onRegister( \PartKeepr\Printing\RendererFactoryRegistry + * $registry ) to your class which will be called to integrate your plugin. */ interface RendererIfc{ /** diff --git a/src/backend/PartKeepr/Printing/SimpleRendererFactory.php b/src/backend/PartKeepr/Printing/SimpleRendererFactory.php @@ -16,12 +16,37 @@ use PartKeepr\Printing\PageBasicLayout\PageBasicLayout; * __construct( PrintingPageBasicLayout $layout, array $configuration ) */ class SimpleRendererFactory implements RendererFactoryIfc{ + /** + * This is the display name for the user of the underlaying renderer. + * + * @var string + */ private $name; + /** + * This is the class name with full namespace path of the class created from + * this factory. This value will be used to have an unique reference name + * to find a class. + * + * @var string + */ private $className; + /** + * This array holds all names for supported data classes. These data classes + * can be handled by the renderer via its passRenderingData method. + * + * @var array of strings + */ private $supportedClasses; + /** + * The array of configuration parameters the renderer needs to operate. + * This array holds strings off class names with full namespace. They must be + * passed to the createInstance via the $configuration parameter. + * + * @var array of string + */ private $neededParameterObjectTypes; /** @@ -30,6 +55,7 @@ class SimpleRendererFactory implements RendererFactoryIfc{ * @param string $name * @param string $className * @param array $supportedClasses + * @param array $neededParameterObjectTypes */ public function __construct( $name, $className, array $supportedClasses, array $neededParameterObjectTypes){ $this->name = $name; @@ -38,22 +64,42 @@ class SimpleRendererFactory implements RendererFactoryIfc{ $this->neededParameterObjectTypes = $neededParameterObjectTypes; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererFactoryIfc::createInstance() + */ public function createInstance(array $objects, $configuration){ return new $this->className($objects, $configuration); } + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererFactoryIfc::getName() + */ public function getName(){ return $this->name; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererFactoryIfc::getCreatedClassname() + */ public function getCreatedClassname(){ return $this->className; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererFactoryIfc::getSupportedClassesForRendering() + */ public function getSupportedClassesForRendering(){ return $this->supportedClasses; } + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererFactoryIfc::getParameterObjectTypes() + */ public function getParameterObjectTypes(){ return $this->neededParameterObjectTypes; } diff --git a/src/backend/PartKeepr/Printing/Utils/DecodeConfiguration.php b/src/backend/PartKeepr/Printing/Utils/DecodeConfiguration.php @@ -2,6 +2,7 @@ namespace PartKeepr\Printing\Utils; use PartKeepr\Printing\Exceptions\InvalidArgumentException; +use PartKeepr\PartKeepr; /** * Helper class which enables us to decode a configuration which was passed as JSON diff --git a/src/backend/PartKeepr/Printing/Utils/Placeholder.php b/src/backend/PartKeepr/Printing/Utils/Placeholder.php @@ -17,6 +17,18 @@ class Placeholder{ private $replacements = array(); /** + * This is the passed begin token for detection at the beginning. + * @var string + */ + private $beginToken; + + /** + * This is the passed end token for detecting the end of the replacement. + * @var string + */ + private $endToken; + + /** * Constructs a new placeholder class and use the object to fill * the placeholder with. * @@ -27,6 +39,7 @@ class Placeholder{ if ( $object instanceof Part ){ $replace = array( 'id' => $object->getId(), + 'barcodeId' => $object->getId() * 10 + 1, 'name' => $object->getName(), 'internalNumber' => $object->getInternalPartNumber(), 'description' => $object->getDescription(), @@ -35,12 +48,17 @@ class Placeholder{ 'footprintName' => $object->getFootprint() === null ? '': $object->getFootprint()->getName(), 'storageLocationName' => $object->getStorageLocation() === null ? '': $object->getStorageLocation()->getName() ); + }else if ( $object instanceof StorageLocation ){ + $replace = array( + 'id' => $object->getId(), + 'barcodeId' => $object->getId() * 10 + 2, + 'name' => $object->getName() + ); } - // Finally apply begin and ends. - foreach( $replace as $key => $value ){ - $this->replacements[$begin.$key.$end] = $value; - } + $this->beginToken = $begin; + $this->endToken = $end; + $this->replacements = $replace; } /** @@ -49,7 +67,26 @@ class Placeholder{ * @param string $text Text to replace the placeholders in. */ public function apply( $text ){ - return strtr($text, $this->replacements); + $beginEscaped = preg_quote( $this->beginToken, '/'); + $endEscaped = preg_quote( $this->endToken, '/'); + + $replacements = $this->replacements; + $callback = function( $matches ) use ($replacements) { + if (!array_key_exists($matches[1],$replacements)) + return "Error: Unknown field!"; + $filedContent = $replacements[$matches[1]]; + if (strlen($matches[2])==0){ + return $filedContent; + }else{ + return sprintf($matches[3],$filedContent); + } + }; + + $regex = '/'.$beginEscaped."([a-zA-Z]+)(|,(.*?))".$endEscaped.'/'; + $text = preg_replace_callback( $regex + , $callback, $text); + + return $text; } } \ No newline at end of file diff --git a/src/backend/Plugins/PrintingRenderer/PDFDefaultRenderer/PDFDefaultRenderer.php b/src/backend/Plugins/PrintingRenderer/PDFDefaultRenderer/PDFDefaultRenderer.php @@ -0,0 +1,233 @@ +<?php +namespace PartKeepr\Printing\Renderer\PDFDefaultRenderer; + +use PartKeepr\Part\Part, + PartKeepr\Printing\Exceptions\RendererNotFoundException, + PartKeepr\Printing\PageBasicLayout\PageBasicLayout, + PartKeepr\Printing\RendererFactoryRegistry, + PartKeepr\Printing\Renderer\PDFDefaultRenderer\TCPDFAbstractRenderer, + PartKeepr\Printing\SimpleRendererFactory, + PartKeepr\Printing\Utils\PercentOrNumericHelper, + PartKeepr\Printing\Utils\Placeholder, + PartKeepr\Printing\Utils\DecodeConfiguration, + PartKeepr\StorageLocation\StorageLocation + ; + +/** + * This class implements a way to render different datasets to + * a labeling layout. + */ +class PDFDefaultRenderer extends TCPDFAbstractRenderer{ + /** + * Our default configuration for this label renderer. + * @var array + */ + private $defaultConfiguration = array( + 'barcodeEnable' => false, + 'barcodeType' => 'QRCODE,L', + 'textBarcode' => "!!barcodeId,%06d!!", + 'barcodeWidth' => "12", + 'barcodeHeight' => "12", + 'barcodeXPos' => "-7", + 'barcodeYPos' => "7", + 'barcodeWithText' => false, + 'barcode2D' => true, + 'fontFamily' => 'times', + 'fontStyle' => '', + 'fontSize' => 12, + 'text' => '<span style="font-size: 11pt;"><b>!!name!!</b></span><br><span style="font-size: 8pt;">!!description!!</span>', + 'textXOffset' => 0, + 'textYOffset' => 0 + ); + + /** + * @param array $objects needs at least an instance of the PageBasicLayout. + * @param unknown $cfgString The configuration string. + */ + public function __construct (array $objects, $cfgString ) { + $configuration = DecodeConfiguration::decode($cfgString); + + // Apply the personal default configuration here. + // The base will apply the base default parameters for you. + $configuration = array_merge( $this->defaultConfiguration, $configuration ); + parent::__construct( $objects, $configuration); + } + + public function passRenderingData( $data ){ + // Here we got our data passed. We have to decide how we want + // to render the data, so we dispatch it to our internal rendering + // methods to make the code more clear. + if ( is_array( $data ) ){ + if (count($data)>0){ + $elem = reset($data); + if ($elem instanceof StorageLocation || $elem instanceof Part ){ + $this->renderObjects($data); + }else{ + throw new RendererNotFoundException("Unable to handle object type with renderer PDFLabelRenderer.", + get_class($elem),array("StorageLocation","Part")); + } + } + } + else{ + // If the selected object is not an array, we make an array first + // to have only one case to handle. + passRenderingData( array( $ata ) ); + } + } + + /** + * This method renders an array of Parts to our sheet. + * @param array $parts + */ + private function renderObjects( array $objects ){ + foreach ($objects as $obj){ + $this->renderCell( $obj ); + } + } + + /** + * This method just renders the next single cell with a part + * as content. + */ + private function renderCell( $object ){ + // Move the pointer to the next cell and initialize PDF class + // correctly. Also draws the grid if necessary. + $this->initNextCell(); + + $padding = 3; + + $dataReplacement = new Placeholder( $object, "!!", "!!" ); + + $text = $dataReplacement->apply($this->configuration['text']); + $barcodeId = $dataReplacement->apply($this->configuration['textBarcode'] ); + + $this->pdf->SetCellPadding($padding); + $this->pdf->SetFont( $this->configuration['fontFamily'], + $this->configuration['fontStyle'], + $this->configuration['fontSize']); + $this->pdf->SetXY( $this->xCellPos,$this->yCellPos ); + + if ($this->configuration['barcodeEnable']){ + $widthParameter = new PercentOrNumericHelper($this->configuration['barcodeWidth']); + $heightParameter = new PercentOrNumericHelper($this->configuration['barcodeHeight']); + $xPosParameter = new PercentOrNumericHelper($this->configuration['barcodeXPos']); + $yPosParameter = new PercentOrNumericHelper($this->configuration['barcodeYPos']); + + $xPos = $xPosParameter->getValueWrap(0, $this->layout->getCellWidthInMM() ); + $yPos = $yPosParameter->getValueWrap(0, $this->layout->getCellHeightInMM() ); + $width = $widthParameter->getValue(0,$this->layout->getCellWidthInMM()); + $height = $heightParameter->getValue(0,$this->layout->getCellHeightInMM()); + + $regions = array(); + + // Shitty workaround for a Bug in TCPDF the ower is not interested in fixing it! + $this->pdf->resetInternalMargins(); + + if ($this->configuration['barcode2D']){ + $this->pdf->write2DBarcode($barcodeId, $this->configuration['barcodeType'], + $this->xCellPos + $xPos - $width / 2 , + $this->yCellPos + $yPos - $height / 2, + $width, + $height + ); + } else { + $style = array('text'=> $this->configuration['barcodeWithText'] ); + $this->pdf->write1DBarcode($barcodeId, $this->configuration['barcodeType'], + $this->xCellPos + $xPos - $width / 2 , + $this->yCellPos + $yPos - $height / 2, + $width, + $height, + "", + $style + ); + } + + // This region will add a "do not write text here" over our barcode This is a kind + // of hack to make text fluently moving around :) + $textMarginX = 7; + $textMarginY = 7; + + $left = $xPos < $this->layout->getCellWidthInMM() / 2; + $top = $yPos < $this->layout->getCellHeightInMM() / 2; + + // $this->pdf->writeHTML("LEFT: $left TOP: $top XPOS: $xPos YPOS: $yPos WIDTH: ".$this->layout->getCellWidthInMM()." HEIGHT: ".$this->layout->getCellHeightInMM(), true, false, true, false, ''); + if( $left ) + { + if( $top ){ + $regions[] = array('page' => '' + , 'xt' => $xPos + $this->xCellPos + $textMarginX + , 'yt' => 0 + , 'xb' => $xPos + $this->xCellPos + $textMarginX + , 'yb' => $yPos + $this->yCellPos + $textMarginY, 'side' => 'L'); + }else + { + $regions[] = array('page' => '' + , 'xt' => $xPos + $this->xCellPos + $textMarginX + , 'yt' => $yPos + $this->yCellPos - $textMarginY + , 'xb' => $xPos + $this->xCellPos + $textMarginX + , 'yb' => $this->yCellPos + $this->layout->getCellHeightInMM() + , 'side' => 'L'); + } + }else + { + if( $top ){ + $regions[] = array('page' => '' + , 'xt' => $xPos + $this->xCellPos - $textMarginX + , 'yt' => 0 + , 'xb' => $xPos + $this->xCellPos - $textMarginX + , 'yb' => $yPos + $this->yCellPos + $textMarginY, 'side' => 'R'); + }else + { + $regions[] = array('page' => '' + , 'xt' => $xPos + $this->xCellPos - $width / 2 - $textMarginX + , 'yt' => $yPos + $this->yCellPos - $height/ 2 - $textMarginY + , 'xb' => $xPos + $this->xCellPos - $width / 2 - $textMarginX + , 'yb' => $this->yCellPos + $this->layout->getCellHeightInMM() + , 'side' => 'R'); + } + } + $this->pdf->setPageRegions($regions); + } + + // Start clipping. Every thing with StartTransform and StopTransform + // will be clipped to the Rect. This is a cool feature if one field is + // too long, it will not destroy the rest of your page and it is partial + // usable. + $this->pdf->StartTransform(); + // Draw clipping rectangle to match html cell. + $this->pdf->Rect($this->xCellPos, $this->yCellPos, $this->layout->getCellWidthInMM(), + $this->layout->getCellHeightInMM(), 'CNZ'); + + $xPosTextOffsetParameter = new PercentOrNumericHelper($this->configuration['textXOffset']); + $yPosTextOffsetParameter = new PercentOrNumericHelper($this->configuration['textYOffset']); + + $this->pdf->WriteHTMLCell( $this->layout->getCellWidthInMM(), + $this->layout->getCellHeightInMM(), + $this->xCellPos + $xPosTextOffsetParameter->getValueUnbound( $this->layout->getCellWidthInMM() ), + $this->yCellPos + $yPosTextOffsetParameter->getValueUnbound( $this->layout->getCellWidthInMM() ), + $text); + + $this->pdf->StopTransform(); + + $this->pdf->setPageRegions(); + } + + /** + * Registers this renderer class to the registry. + * + * @param RendererFactoryRegistry $registry + */ + public static function onRegister( RendererFactoryRegistry $registry ){ + // We have to register this class to the registry. + // Only if the class is registered, it can be found by the + // registry and you will see it in the application. + $registry->registerFactory( + new SimpleRendererFactory("Default PDF renderer", + "PartKeepr\Printing\Renderer\PDFDefaultRenderer\PDFDefaultRenderer", + array("PartKeepr\StorageLocation\StorageLocation", + "PartKeepr\Part\Part"), + array("PartKeepr\Printing\PageBasicLayout\PageBasicLayout") + ) + ); + } +} diff --git a/src/backend/Plugins/PrintingRenderer/PDFDefaultRenderer/TCPDFAbstractRenderer.php b/src/backend/Plugins/PrintingRenderer/PDFDefaultRenderer/TCPDFAbstractRenderer.php @@ -0,0 +1,205 @@ +<?php +namespace PartKeepr\Printing\Renderer\PDFDefaultRenderer; + +use PartKeepr\Printing\RendererIfc, + PartKeepr\Printing\RendererFactoryRegistry, + PartKeepr\Printing\RendererNotFoundException, + PartKeepr\Printing\SimpleRendererFactory, + PartKeepr\Printing\PageBasicLayout\PageBasicLayout, + PartKeepr\StorageLocation\StorageLocation + ; + +require_once('tcpdf/tcpdf.php'); + +/** + * This wrapper class can be used to remove some bugs from the + * TCPDF. https://sourceforge.net/p/tcpdf/bugs/773/ + * @author sven + * + */ +class TCPDFWrapper extends \TCPDF{ + public function __construct($orientation, $unit, $format){ + parent::__construct($orientation, $unit, $format); + } + + public function resetInternalMargins(){ + $this->crMargin = $this->rMargin = $this->original_rMargin; + $this->clMargin = $this->lMargin = $this->original_lMargin; + } +} + +/** + * This class is a abstract renderer to help somebody by creating its + * own plugins. Use the PDFDefaultRenderer as an example. + */ +abstract class TCPDFAbstractRenderer implements RendererIfc{ + /** + * This contains our layout for the page to be rendered. + */ + protected $layout = null; + + /** + * Our internal used pdf generator. + */ + protected $pdf; + + /** + * This is the count of the cells we have actually rendered. You can name + * it a pointer to the next cell, which should be rendered. We render all + * columns first and then increment the row. + */ + protected $cellsRendered; + + /** + * This is the position of the actual cell we want to process. + * Top left point. + */ + protected $xCellPos = 0; + + /** + * This is the position of the actual cell we want to process. + * Top left point. + */ + protected $yCellPos = 0; + + /** + * This is an array with configuration things. + * @var array + */ + protected $configuration; + + /** + * This boolean can be set to true to not trigger an error on startup. + * We implement it this way, to ensure the implementer of the plugin has + * thought of this potential security risk. + * + * @var unknown + */ + protected $doNotErrorIfTCPDFSetsCalls = false; + + /** + * Our default configuration for this label renderer. + * @var array + */ + protected $basedefaultConfiguration = array( + 'borderGrid' => true, + 'startingCell' => 0 + ); + + public function __construct ( array $objects, array $configuration ) { + foreach( $objects as $obj ){ + if ($obj instanceof \PartKeepr\Printing\PageBasicLayout\PageBasicLayout){ + $this->layout = $obj; + } + } + + if ($this->layout === null){ + throw new \PartKeepr\Printing\Exceptions\InvalidArgumentException("Required object not passed!"); + } + + $this->configuration = array_merge( $this->basedefaultConfiguration, $configuration ); + + $this->cellsRendered = $this->configuration['startingCell']; + + if (K_TCPDF_CALLS_IN_HTML && !$doNotErrorIfTCPDFSetsCalls){ + trigger_error("TCPDF has set K_TCPDF_CALLS_IN_HTML to true, which is a security issue with this class since the user can modify the html text!",E_USER_ERROR); + } + + $this->pdf = new TCPDFWrapper( $this->layout->getPaperPortrait() ? 'P': 'L' + , 'mm', $this->layout->getPaperSize() ); + + // set document information + $this->pdf->SetCreator(PDF_CREATOR); + $this->pdf->SetAuthor('PartDB'); + $this->pdf->SetTitle('PartDB Labeling Document'); + $this->pdf->SetSubject('This is a priontout of for labeling or indexing'); + $this->pdf->SetKeywords('PartDB'); + + // remove default header/footer + $this->pdf->setPrintHeader(false); + $this->pdf->setPrintFooter(false); + + // set default monospaced font + $this->pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); + + //set margins + $this->pdf->SetMargins(0, 0, 0); + + //set auto page breaks + $this->pdf->SetAutoPageBreak(FALSE, 0); + + //set image scale factor + $this->pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + + //set some language-dependent strings + //$this->pdf->setLanguageArray($l); + + // --------------------------------------------------------- + } + + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererIfc::getSuggestedExtension() + */ + public function getSuggestedExtension(){ + return "pdf"; + } + + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererIfc::storeResult() + */ + public function storeResult( $outFile ){ + $this->pdf->Output($outFile, 'F'); + } + + /** + * + * @param unknown $filename + */ + public function outputResult($filename){ + $this->pdf->Output($filename, 'I'); + } + + /** + * Renders a border grid which is based on the layout. + */ + protected function renderBorderGrid(){ + $colYStart = $this->layout->getTopLeftYInMM(); + $colYEnd = $this->layout->getRowCount() * $this->layout->getCellHeightInMM() + $this->layout->getTopLeftYInMM(); + + $rowXStart = $this->layout->getTopLeftXInMM(); + $rowXEnd = $this->layout->getColumnCount() * $this->layout->getCellWidthInMM() + $this->layout->getTopLeftXInMM(); + + for ($r=0; $r <= $this->layout->getRowCount(); $r++){ + $rowYPos = $r * $this->layout->getCellHeightInMM() + $this->layout->getTopLeftYInMM(); + $this->pdf->Line( $rowXStart, $rowYPos, $rowXEnd, $rowYPos ); + } + + for ($c=0; $c <= $this->layout->getColumnCount(); $c++){ + $colXPos = $c * $this->layout->getCellWidthInMM() + $this->layout->getTopLeftXInMM(); + $this->pdf->Line( $colXPos, $colYStart, $colXPos, $colYEnd ); + } + } + + /** + * Opens the cell and sets the class to the correct coordinates. + */ + protected function initNextCell(){ + $page = floor( $this->cellsRendered / ($this->layout->getColumnCount() * $this->layout->getRowCount())); + $cellXCoordinate = $this->cellsRendered % $this->layout->getColumnCount(); + $cellYCoordinate = ( floor($this->cellsRendered / $this->layout->getColumnCount()) ) % $this->layout->getRowCount() ; + + $this->xCellPos = $cellXCoordinate * $this->layout->getCellWidthInMM() + $this->layout->getTopLeftXInMM(); + $this->yCellPos = $cellYCoordinate * $this->layout->getCellHeightInMM() + $this->layout->getTopLeftYInMM(); + + if ($cellXCoordinate == 0 && $cellYCoordinate == 0){ + $this->pdf->AddPage(); + if ($this->configuration['borderGrid']){ + $this->renderBorderGrid(); + } + } + + $this->cellsRendered++; + } +} diff --git a/src/backend/Plugins/PrintingRenderer/ZebraLabelWriterRenderer/ZebraLabelWriterRenderer.php b/src/backend/Plugins/PrintingRenderer/ZebraLabelWriterRenderer/ZebraLabelWriterRenderer.php @@ -0,0 +1,165 @@ +<?php +namespace PartKeepr\Printing\Renderer\ZebraLabelWriterRenderer; + +use PartKeepr\Part\Part, + PartKeepr\Printing\PageBasicLayout\PageBasicLayout, + PartKeepr\Printing\RendererFactoryRegistry, + PartKeepr\Printing\RendererIfc, + PartKeepr\Printing\SimpleRendererFactory, + PartKeepr\Printing\Exceptions\RendererNotFoundException, + PartKeepr\Printing\Utils\DecodeConfiguration, + PartKeepr\Printing\Utils\Placeholder, + PartKeepr\StorageLocation\StorageLocation + ; + +/** + * This class implements a printing renderer which renders the data + * to the ZPL printing language. The idea behind is to create a template using + * the Designer software provided by Zebra, print it to a file and then use this + * file as a template here. + */ +class ZebraLabelWriterRenderer implements RendererIfc{ + /** + * Our default configuration for this label renderer. + * @var array + */ + private $defaultConfiguration = array( + 'template' => +<<<'EOD' +CT~~CD,~CC^~CT~ +^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA^PR3,3~SD8^JUS^LRN^CI0^XZ +^XA +^MMT +^PW320 +^LL0176 +^LS0 +^FT16,44^A0N,34,33^FH\^FD<<name>>^FS +^FT16,76^A0N,23,24^FH\^FD<<description>>^FS +^BY3,3,33^FT49,146^BCN,,Y,N +^FD>;<<barcodeId,%06d>>^FS +^PQ1,0,1,Y^XZ +EOD + ); + + /** + * The rendered data up to now. + */ + protected $out = ""; + + /** + * This is the current active configuration. + * @var unknown + */ + protected $configuration; + + /** + * This is the configuration passed to this class. + * @var unknown + */ + protected $configurationIn; + + /** + * @param array $obj dummy, not needed. + * @param unknown $cfgString The configuration string. + */ + public function __construct (array $obj, $cfgString ) { + $configuration = DecodeConfiguration::decode($cfgString); + $this->configurationIn = $configuration; + } + + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererIfc::passRenderingData() + */ + public function passRenderingData( $data ){ + // Here we got our data passed. We have to decide how we want + // to render the data, so we dispatch it to our internal rendering + // methods to make the code more clear. + if ( is_array( $data ) ){ + if (count($data)>0){ + $elem = reset($data); + if ($elem instanceof StorageLocation || $elem instanceof Part){ + $this->renderObjects($data); + } + else{ + throw new RendererNotFoundException("Unable to handle object type with this renderer.", + get_class($elem),array("StorageLocation","Part")); + } + } + } + else{ + // If the selected object is not an array, we make an array first + // to have only one case to handle. + passRenderingData( array( $ata ) ); + } + } + + /** + * This method renders an array of Objects to our labels. + * @param array $objects + */ + private function renderObjects( array $objects ){ + $this->configuration = array_merge( $this->defaultConfiguration, $this->configurationIn ); + + foreach ($objects as $obj){ + $this->renderSingleObject( $obj ); + } + } + + + /** + * Just render a single object to the output. + * + * @param $object + */ + private function renderSingleObject( $object ){ + $dataReplacement = new Placeholder( $object, "<<", ">>"); + $this->out .= $dataReplacement->apply($this->configuration['template']) . "\n"; + } + + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererIfc::getSuggestedExtension() + */ + public function getSuggestedExtension(){ + return "zpl"; + } + + /** + * (non-PHPdoc) + * @see \PartKeepr\Printing\RendererIfc::storeResult() + */ + public function storeResult( $outFile ){ + $file = fopen($outFile,'w'); + fwrite( $file, $this->out ); + fclose( $file ); + } + + /** + * + * @param unknown $filename + * @return string + */ + public function outputResult($filename){ + return $this->out; + } + + /** + * Registers this renderer class to the registry. + * + * @param RendererFactoryRegistry $registry + */ + public static function onRegister( RendererFactoryRegistry $registry ){ + // We have to register this class to the registry. + // Only if the class is registered, it can be found by the + // registry and you will see it in the application. + $registry->registerFactory( + new SimpleRendererFactory("Zebra Label Renderer", + "PartKeepr\Printing\Renderer\ZebraLabelWriterRenderer\ZebraLabelWriterRenderer", + array("PartKeepr\Part\Part","PartKeepr\StorageLocation\StorageLocation"), + array() + ) + ); + } +} + diff --git a/src/frontend/js/Components/Part/Editor/PartEditorWindow.js b/src/frontend/js/Components/Part/Editor/PartEditorWindow.js @@ -19,12 +19,16 @@ Ext.define('PartKeepr.PartEditorWindow', { height: 415, saveText: i18n("Save"), + saveAndPrintText: i18n("Save + Print"), + printText: i18n("Print"), cancelText: i18n("Cancel"), /* Default edit mode. If mode = "create", we show additional fields */ partMode: 'edit', title: i18n("Add Part"), + saveButtonReenableTask: null, + /** * Creates the part editor and put it into the window. */ @@ -64,13 +68,25 @@ Ext.define('PartKeepr.PartEditorWindow', { handler: Ext.bind(this.onCancelEdit, this) }); + this.saveAndPrintButton = Ext.create("Ext.button.Button", { + text: this.saveAndPrintText, + icon: 'resources/fugue-icons/icons/printer.png', + handler: Ext.bind(this.onItemSaveAndPrint, this) + }); + + this.printButton = Ext.create("Ext.button.Button", { + text: this.printText, + icon: 'resources/fugue-icons/icons/printer.png', + handler: Ext.bind(this.onItemPrint, this) + }); + this.bottomToolbar = Ext.create("Ext.toolbar.Toolbar", { enableOverflow: true, defaults: {minWidth: 100}, dock: 'bottom', ui: 'footer', pack: 'start', - items: [ this.saveButton, this.cancelButton ] + items: [ this.saveButton, this.cancelButton, this.partMode == "create" ? this.saveAndPrintButton : this.printButton ] }); this.dockedItems = [ this.bottomToolbar ]; @@ -127,11 +143,38 @@ Ext.define('PartKeepr.PartEditorWindow', { this.saveButton.disable(); // Sanity: If the save process fails, re-enable the button after 30 seconds - Ext.defer(function () { this.saveButton.enable(); }, 30000, this); - + if (this.saveButtonReenableTask === null){ + this.saveButtonReenableTask = new Ext.util.DelayedTask(function(){ this.saveButton.enable(); }, this); + this.on( 'destroy', function(){ this.saveButtonReenableTask.cancel(); }, this ); + } + this.saveButtonReenableTask.delay(30000); + this.editor._onItemSave(); }, /** + * Prints the currently shown part. Only possible if the part was saved before. + */ + onItemPrint: function() { + this.printItem(this.editor.record.data.id); + }, + /** + * Prints a single part which is identified by its id. + */ + printItem: function( id ){ + var val = Ext.create("PartKeepr.PrintingWindow"); + val.setObjectType('PartKeepr\\Part\\Part'); + val.setContext("PartEditor"); + val.setObjectIds([id]); + val.show(); + }, + /** + * Called if one presses the save and print button. + */ + onItemSaveAndPrint: function () { + this.editor.on("itemSaved", function(record){ this.printItem(record.data.id);}, this, {"single": true}); + this.onItemSave(); + }, + /** * Called when the item was saved */ onItemSaved: function () { diff --git a/src/frontend/js/Components/Printing/PrintingWindow.js b/src/frontend/js/Components/Printing/PrintingWindow.js @@ -19,6 +19,8 @@ Ext.define('PartKeepr.PrintingWindow', { modal: true, + context: "", + executeText: i18n("Print"), cancelText: i18n("Cancel"), @@ -109,9 +111,20 @@ Ext.define('PartKeepr.PrintingWindow', { setObjectType: function( objectType ) { this.objectType = objectType; this.configurationStore.filter('objectType', objectType ); - - this.configurationSelector.setValue( PartKeepr.getApplication().getUserPreference("partkeepr.printing.lastUsedConfiguration."+objectType),'' ); - this.targetSelector.setValue( PartKeepr.getApplication().getUserPreference("partkeepr.printing.lastUsedTarget."+objectType),'' ); + this.loadLastUsed(); + }, + /** + * Sets the window context to store last used values for this context. + * Context needs to be a string, which identifies it. + */ + setContext: function( context ) { + this.context = context; + this.loadLastUsed(); + }, + loadLastUsed: function() { + var context = this.context.length > 0 ? this.context : this.objectType; + this.configurationSelector.setValue( PartKeepr.getApplication().getUserPreference("partkeepr.printing.lastUsedConfiguration."+context),'' ); + this.targetSelector.setValue( PartKeepr.getApplication().getUserPreference("partkeepr.printing.lastUsedTarget."+context),'' ); }, /** * Set the ids of the objects which should be printed/exported @@ -132,8 +145,8 @@ Ext.define('PartKeepr.PrintingWindow', { if (config!==null){ executor.executePrint( config, this.objectType, this.objectIds, target); if (this.objectType!==null){ - PartKeepr.getApplication().setUserPreference("partkeepr.printing.lastUsedConfiguration."+this.objectType, this.configurationSelector.getValue() ); - PartKeepr.getApplication().setUserPreference("partkeepr.printing.lastUsedTarget."+this.objectType, this.targetSelector.getValue() ); + PartKeepr.getApplication().setUserPreference("partkeepr.printing.lastUsedConfiguration."+this.context, this.configurationSelector.getValue() ); + PartKeepr.getApplication().setUserPreference("partkeepr.printing.lastUsedTarget."+this.context, this.targetSelector.getValue() ); } this.close(); diff --git a/src/frontend/js/Components/Widgets/DistributorComboBox.js b/src/frontend/js/Components/Widgets/DistributorComboBox.js @@ -1,27 +1,9 @@ Ext.define("PartKeepr.DistributorComboBox",{ - extend:"Ext.form.field.ComboBox", + extend:"PartKeepr.ReloadableComboBox", alias: 'widget.DistributorComboBox', - displayField: 'name', - valueField: 'id', - autoSelect: true, - queryMode: 'local', - triggerAction: 'all', - forceSelection: true, - editable: true, ignoreQuery: false, initComponent: function () { this.store = PartKeepr.getApplication().getDistributorStore(); - - /* Workaround to remember the value when loading */ - this.store.on("beforeload", function () { - this._oldValue = this.getValue(); - }, this); - - /* Set the old value when load is complete */ - this.store.on("load", function () { - this.setValue(this._oldValue); - }, this); - this.callParent(); }, onTriggerClick: function() { @@ -42,4 +24,3 @@ Ext.define("PartKeepr.DistributorComboBox",{ } }); - diff --git a/src/frontend/js/Components/Widgets/FootprintComboBox.js b/src/frontend/js/Components/Widgets/FootprintComboBox.js @@ -1,26 +1,8 @@ Ext.define("PartKeepr.FootprintComboBox",{ - extend:"Ext.form.field.ComboBox", + extend:"PartKeepr.ReloadableComboBox", alias: 'widget.FootprintComboBox', - displayField: 'name', - valueField: 'id', - autoSelect: true, - queryMode: 'local', - triggerAction: 'all', - forceSelection: true, - editable: true, initComponent: function () { this.store = PartKeepr.getApplication().getFootprintStore(); - - /* Workaround to remember the value when loading */ - this.store.on("beforeload", function () { - this._oldValue = this.getValue(); - }, this); - - /* Set the old value when load is complete */ - this.store.on("load", function () { - this.setValue(this._oldValue); - }, this); - this.callParent(); } }); diff --git a/src/frontend/js/Components/Widgets/ManufacturerComboBox.js b/src/frontend/js/Components/Widgets/ManufacturerComboBox.js @@ -1,27 +1,8 @@ Ext.define("PartKeepr.ManufacturerComboBox",{ - extend:"Ext.form.field.ComboBox", + extend:"PartKeepr.ReloadableComboBox", alias: 'widget.ManufacturerComboBox', - displayField: 'name', - valueField: 'id', - autoSelect: true, - queryMode: 'local', - triggerAction: 'all', - forceSelection: true, - editable: true, initComponent: function () { this.store = PartKeepr.getApplication().getManufacturerStore(); - - /* Workaround to remember the value when loading */ - this.store.on("beforeload", function () { - this._oldValue = this.getValue(); - }, this); - - /* Set the old value when load is complete */ - this.store.on("load", function () { - this.setValue(this._oldValue); - }, this); - this.callParent(); } }); - diff --git a/src/frontend/js/Components/Widgets/PartUnitComboBox.js b/src/frontend/js/Components/Widgets/PartUnitComboBox.js @@ -1,27 +1,8 @@ Ext.define("PartKeepr.PartUnitComboBox",{ - extend:"Ext.form.field.ComboBox", + extend:"PartKeepr.ReloadableComboBox", alias: 'widget.PartUnitComboBox', - displayField: 'name', - valueField: 'id', - autoSelect: true, - queryMode: 'local', - triggerAction: 'all', - forceSelection: true, - editable: true, initComponent: function () { this.store = PartKeepr.getApplication().getPartUnitStore(); - - /* Workaround to remember the value when loading */ - this.store.on("beforeload", function () { - this._oldValue = this.getValue(); - }, this); - - /* Set the old value when load is complete */ - this.store.on("load", function () { - this.setValue(this._oldValue); - }, this); - this.callParent(); } }); - diff --git a/src/frontend/js/Components/Widgets/ReloadableComboBox.js b/src/frontend/js/Components/Widgets/ReloadableComboBox.js @@ -0,0 +1,23 @@ +Ext.define("PartKeepr.ReloadableComboBox",{ + extend:"Ext.form.field.ComboBox", + alias: 'widget.ReloadableComboBox', + displayField: 'name', + valueField: 'id', + autoSelect: true, + queryMode: 'local', + triggerAction: 'all', + forceSelection: true, + editable: true, + initComponent: function () { + this.listenersStore = this.store.mon({ + item: this, + scope: this, + // Workaround to remember the value when loading + beforeload: function () { this._oldValue = this.getValue(); }, + // Set the old value when load is complete + load: function () { this.setValue(this._oldValue); } + }); + + this.callParent(); + } +}); diff --git a/src/frontend/js/Components/Widgets/UnitComboBox.js b/src/frontend/js/Components/Widgets/UnitComboBox.js @@ -1,27 +1,8 @@ Ext.define("PartKeepr.UnitComboBox",{ - extend:"Ext.form.field.ComboBox", + extend:"PartKeepr.ReloadableComboBox", alias: 'widget.UnitComboBox', - displayField: 'name', - valueField: 'id', - autoSelect: true, - queryMode: 'local', - triggerAction: 'all', - forceSelection: true, - editable: true, initComponent: function () { this.store = PartKeepr.getApplication().getUnitStore(); - - /* Workaround to remember the value when loading */ - this.store.on("beforeload", function () { - this._oldValue = this.getValue(); - }, this); - - /* Set the old value when load is complete */ - this.store.on("load", function () { - this.setValue(this._oldValue); - }, this); - this.callParent(); } }); - diff --git a/src/frontend/js/Components/Widgets/UserComboBox.js b/src/frontend/js/Components/Widgets/UserComboBox.js @@ -1,27 +1,8 @@ Ext.define("PartKeepr.UserComboBox",{ - extend:"Ext.form.field.ComboBox", + extend:"PartKeepr.ReloadableComboBox", alias: 'widget.UserComboBox', - displayField: 'username', - valueField: 'id', - autoSelect: true, - queryMode: 'local', - triggerAction: 'all', - forceSelection: true, - editable: true, initComponent: function () { this.store = PartKeepr.getApplication().getUserStore(); - - /* Workaround to remember the value when loading */ - this.store.on("beforeload", function () { - this._oldValue = this.getValue(); - }, this); - - /* Set the old value when load is complete */ - this.store.on("load", function () { - this.setValue(this._oldValue); - }, this); - this.callParent(); } }); -