Merge branch '2013.03' into pu/2013.03/modelconfig-hr
authorPhilipp Schüle <p.schuele@metaways.de>
Tue, 20 Aug 2013 14:18:13 +0000 (16:18 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Tue, 20 Aug 2013 14:18:13 +0000 (16:18 +0200)
Conflicts:
tests/tine20/Calendar/JsonTests.php
tine20/Felamimail/Controller/Message/Send.php
tine20/HumanResources/js/ContractGridPanel.js
tine20/Phone/Frontend/Json.php
tine20/Phone/translations/template.pot
tine20/Sales/js/Models.js
tine20/Timetracker/translations/template.pot
tine20/Tinebase/Exception.php
tine20/Tinebase/Server/Json.php
tine20/Tinebase/js/widgets/dialog/EditDialog.js
tine20/Tinebase/js/widgets/relation/GenericPickerGridPanel.js
tine20/Tinebase/translations/template.pot
tine20/library/OpenDocument/Document.php

33 files changed:
1  2 
tests/tine20/AllTests.php
tests/tine20/Calendar/Controller/EventNotificationsTests.php
tests/tine20/Calendar/Convert/Event/VCalendar/GenericTest.php
tests/tine20/Calendar/JsonTests.php
tests/tine20/Phone/JsonTest.php
tests/tine20/Sales/JsonTest.php
tests/tine20/TestServer.php
tine20/Admin/Setup/DemoData.php
tine20/Calendar/Controller/Event.php
tine20/Calendar/Model/Event.php
tine20/Felamimail/Controller/Message.php
tine20/Felamimail/Controller/Message/Send.php
tine20/HumanResources/translations/template.pot
tine20/Phone/Controller/MyPhone.php
tine20/Phone/Frontend/Json.php
tine20/Sales/Model/Contract.php
tine20/Sales/js/Models.js
tine20/Sales/translations/template.pot
tine20/Timetracker/translations/template.pot
tine20/Tinebase/Exception.php
tine20/Tinebase/Export.php
tine20/Tinebase/Frontend/Cli.php
tine20/Tinebase/Frontend/Json.php
tine20/Tinebase/Record/Abstract.php
tine20/Tinebase/Record/RecordSet.php
tine20/Tinebase/Server/Json.php
tine20/Tinebase/js/ux/WindowFactory.js
tine20/Tinebase/js/widgets/dialog/EditDialog.js
tine20/Tinebase/js/widgets/grid/GridPanel.js
tine20/Tinebase/js/widgets/relation/GenericPickerGridPanel.js
tine20/Tinebase/translations/de.po
tine20/Tinebase/translations/template.pot
tine20/library/OpenDocument/Document.php

@@@ -46,8 -41,9 +41,9 @@@ class AllTest
          $suite->addTest(HumanResources_AllTests::suite());
          $suite->addTest(Inventory_AllTests::suite());
          $suite->addTest(Sipgate_AllTests::suite());
+         $suite->addTest(SimpleFAQ_AllTests::suite());
          $suite->addTest(Zend_AllTests::suite());
 -        
 +        $suite->addTest(OpenDocument_AllTests::suite());
          return $suite;
      }
  }
@@@ -1311,30 -1300,28 +1311,54 @@@ class Calendar_JsonTests extends Calend
              $this->assertEquals(Calendar_Model_Attender::STATUS_TENTATIVE, $attender['status'], 'both attendee status should be TENTATIVE: ' . print_r($attender, TRUE));
          }
      }
+     /**
+      * testFreeBusyCheckForExdates
+      * 
+      * @see 0008464: freebusy check does not work when creating recur exception
+      */
+     public function testFreeBusyCheckForExdates()
+     {
+         $events = $this->testCreateRecurException();
+         $exception = $this->_getException($events, 1);
+         
+         $anotherEvent = $this->_getEvent(TRUE);
+         $anotherEvent = $this->_uit->saveEvent($anotherEvent->toArray());
+         
+         $exception['dtstart'] = $anotherEvent['dtstart'];
+         $exception['dtend'] = $anotherEvent['dtend'];
+         
+         try {
+             $event = $this->_uit->saveEvent($exception, TRUE);
+             $this->fail('Calendar_Exception_AttendeeBusy expected when saving exception: ' . print_r($exception, TRUE));
+         } catch (Calendar_Exception_AttendeeBusy $ceab) {
+             $this->assertEquals('Calendar_Exception_AttendeeBusy', get_class($ceab));
+         }
+     }
 +    
 +    /**
 +     * testAddAttachmentToRecurSeries
 +     * 
 +     * @see 0005024: allow to attach external files to records
 +     */
 +    public function testAddAttachmentToRecurSeries()
 +    {
 +        $tempFileBackend = new Tinebase_TempFile();
 +        $tempFile = $tempFileBackend->createTempFile(dirname(dirname(__FILE__)) . '/Filemanager/files/test.txt');
 +        
 +        $recurSet = array_value('results', $this->testSearchRecuringIncludes());
 +        // update recurseries 
 +        $someRecurInstance = $recurSet[2];
 +        $someRecurInstance['attachments'] = array(array('tempFile' => array('id' => $tempFile->getId())));
 +        $someRecurInstance['seq'] = 2;
 +        $this->_uit->updateRecurSeries($someRecurInstance, FALSE, FALSE);
 +        
 +        $searchResultData = $this->_searchRecurSeries($recurSet[0]);
 +        foreach ($searchResultData['results'] as $recurInstance) {
 +            $this->assertTrue(isset($recurInstance['attachments']), 'no attachments found in event: ' . print_r($recurInstance, TRUE));
 +            $this->assertEquals(1, count($recurInstance['attachments']));
 +            $attachment = $recurInstance['attachments'][0];
 +            $this->assertEquals('text/plain', $attachment['contenttype'], print_r($attachment, TRUE));
 +        }
 +    }
  }
Simple merge
@@@ -68,10 -69,10 +68,10 @@@ class Sales_JsonTest extends PHPUnit_Fr
      {
          $contract = $this->_getContract();
          $contractData = $this->_instance->saveContract($contract->toArray());
 -
 +        
          // checks
          $this->assertGreaterThan(0, $contractData['number']);
-         $this->assertEquals(Tinebase_Core::getUser()->getId(), $contractData['created_by']);
+         $this->assertEquals(Tinebase_Core::getUser()->getId(), $contractData['created_by']['accountId']);
          
          return $contractData;
      }
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -578,11 -586,13 +586,11 @@@ class Felamimail_Controller_Message_Sen
                  $type = $tempFile->type;
              }
              
 -            $name = Zend_Mime::encodeQuotedPrintableHeader($name, 'utf-8');
 -            $part->disposition = Zend_Mime::DISPOSITION_ATTACHMENT . '; filename="' . $name . '"';
 -            $partTypeString = $type . '; name="' . $name . '"';
 -            $part->type = $partTypeString;
 +            $part->disposition = Zend_Mime::DISPOSITION_ATTACHMENT;
-             $part->setType($type, $name);
++            $part->setTypeAndDispositionForAttachment($type, $name);
              
              if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
 -                . ' Adding attachment ' . $partTypeString);
 +                . ' Adding attachment ' . $part->type);
              
              $_mail->addAttachment($part);
          }
@@@ -443,213 -473,46 +473,183 @@@ msgstr "
  msgid "The title you have chosen is already in use. Please try another one!"
  msgstr ""
  
- #: js/Models.js:72
- msgid "Employees"
- msgid_plural "Employees"
- msgstr[0] ""
- msgstr[1] ""
- #: js/Models.js:106 js/Models.js:199 js/Models.js:297 js/Models.js:365
- msgid "Quick search"
+ #: Setup/Initialize.php:34 Setup/Update/Release6.php:331
+ msgid "Employees which are currently employed"
  msgstr ""
  
- #: js/Models.js:107
- msgid "Employee name"
+ #: Setup/Initialize.php:54
+ msgid "Sickness"
  msgstr ""
  
- #: js/Models.js:120 js/Models.js:382
- msgid "Last Modified Time"
+ #: Setup/Initialize.php:55
+ msgid "Vacation"
  msgstr ""
  
- #: js/Models.js:121 js/Models.js:383
- msgid "Last Modified By"
+ #: Setup/Initialize.php:56
+ msgid "Remaining Vacation"
  msgstr ""
  
- #: js/Models.js:122 js/Models.js:384
- msgid "Creation Time"
+ #: Setup/Initialize.php:57
+ msgid "Extra Vacation"
  msgstr ""
  
- #: js/Models.js:123 js/Models.js:385
- msgid "Created By"
+ #: Setup/Initialize.php:71
+ msgid "Requested"
  msgstr ""
  
- #: js/Models.js:165
- msgid "Working Times"
- msgid_plural "Working Times"
- msgstr[0] ""
- msgstr[1] ""
- #: js/Models.js:230 js/CostCenterGridPanel.js:58
- msgid "CostCenter"
- msgid_plural "CostCenters"
- msgstr[0] ""
- msgstr[1] ""
- #: js/Models.js:234
- msgid "CostCenters"
- msgid_plural "CostCenters"
- msgstr[0] ""
- msgstr[1] ""
- #: js/Models.js:264
- msgid "Contracts"
- msgid_plural "Contracts"
- msgstr[0] ""
- msgstr[1] ""
+ #: Setup/Initialize.php:72
+ msgid "In process"
+ msgstr ""
  
- #: js/Models.js:417
- msgid "Free Day"
- msgid_plural "Free Days"
- msgstr[0] ""
- msgstr[1] ""
+ #: Setup/Initialize.php:73
+ msgid "Accepted"
+ msgstr ""
  
- #: js/Models.js:420
- msgid "Free Days"
- msgid_plural "Free Days"
- msgstr[0] ""
- msgstr[1] ""
+ #: Setup/Initialize.php:74
+ msgid "Declined"
+ msgstr ""
  
- #: js/CostCenterGridPanel.js:104
- msgid "Cost Center"
+ #: Setup/Initialize.php:89 Setup/Update/Release6.php:299
+ msgid "Excused"
  msgstr ""
  
- #: js/CostCenterGridPanel.js:107
- msgid "Startdate"
+ #: Setup/Initialize.php:90 Setup/Update/Release6.php:300
+ msgid "Unexcused"
  msgstr ""
 +
 +
 +msgid "Excused"
 +msgstr ""
 +
 +msgid "Unexcused"
 +msgstr ""
 +
 +msgid "Currently employed"
 +msgstr ""
 +
 +msgid "Employees which are currently employed"
 +msgstr ""
 +
 +msgid "Sickness"
 +msgstr ""
 +
 +msgid "Vacation"
 +msgstr ""
 +
 +msgid "Remaining Vacation"
 +msgstr ""
 +
 +msgid "Extra Vacation"
 +msgstr ""
 +
 +msgid "Requested"
 +msgstr ""
 +
 +msgid "In process"
 +msgstr ""
 +
 +msgid "Accepted"
 +msgstr ""
 +
 +msgid "Declined"
 +msgstr ""
 +
 +msgid "No contract could be found."
 +msgid "Please create a contract for this employee!"
 +msgid "Contract"
 +msgid_plural "Contracts"
 +msgstr[0] ""
 +msgstr[1] ""
 +msgid "Sickness Day"
 +msgid "Sickness Days"
 +msgid "Vacation Day"
 +msgid "Vacation Days"
 +msgid "Add {0}"
 +msgid "CostCenter"
 +msgid_plural "CostCenters"
 +msgstr[0] ""
 +msgstr[1] ""
 +msgid "Cost Center"
 +msgid "Startdate"
 +msgid "Cancel"
 +msgid "OK"
 +msgid "Calendar"
 +msgid "Calendars"
 +msgid "WK"
 +msgid "Loading calendar data..."
 +msgid "Supervisor"
 +msgid "Division"
 +msgid "Employee"
 +msgid "Number"
 +msgid "Account"
 +msgid "Apply contact data on form"
 +msgid "Full Name"
 +msgid "Salutation"
 +msgid "Title"
 +msgid "First Name"
 +msgid "Last Name"
 +msgid "Employment begin"
 +msgstr ""
 +
 +msgid "Employment end"
 +msgstr ""
 +
 +msgid "Edit {0} \"{1}\""
 +msgid "Add {0} for {1}"
 +msgid "Edit {0} for {1}"
 +msgid "Working Time"
 +msgid_plural "Working Times"
 +msgstr[0] ""
 +msgstr[1] ""
 +msgid "Working Times"
 +msgid_plural "Working Times"
 +msgstr[0] ""
 +msgstr[1] ""
 +msgid "Quick search"
 +msgid "Feast Calendar"
 +msgid "Start Date"
 +msgid "End Date"
 +msgid "Free Time"
 +msgid "Free Times"
 +msgid "First Day"
 +msgid "Free Days"
 +msgid "Contracts"
 +msgid "Private Information"
 +msgid "Is employed"
 +msgid "Germany"
 +msgid "Street 2"
 +msgid "Employee name"
 +msgid "Costcenters"
 +msgstr ""
 +msgid "Cost Centers"
 +
 +msgid "Currently employed employees"
 +msgid "All employees"
 +
 +msgid 'Edit {0} for "{1}" - {2}'
 +msgid "Extra free time"
 +msgid_plural "Extra free times"
 +
 +msgid "Personal account"
 +msgid_plural "Personal accounts"
 +
 +msgid "Possible vaction days"
 +msgid "Remaining vaction days"
 +msgid "Taken vaction days 2013"
 +msgid "Excused sickness days"
 +msgid "Unexcused sickness days 2013"
 +msgid "Days to work"
 +msgid "Hours to work"
 +
 +msgid "HumanResources"
 +
 +msgid "Days"
 +msgid "Payed"
 +msgid "Not payed"
 +
 +msgid "Remaining"
 +msgid "Book as vacation"
 +
 +msgid "Summary"
 +
 +msgid "Account is disabled or deleted!"
Simple merge
Simple merge
Simple merge
@@@ -157,8 -158,11 +158,12 @@@ Tine.Sales.Model.Contract.getFilterMode
              keyfieldName: 'contractCleared'
          },
          {label: app.i18n._('Cleared in'), field: 'cleared_in' },
-         {filtertype: 'tinebase.tag', app: app },
-         {filtertype: 'sales.contract.costcenter' }
+         {filtertype: 'tinebase.tag', app: app},
++        {filtertype: 'sales.contract.costcenter' },
+         {label: _('Last Modified Time'), field: 'last_modified_time', valueType: 'date'},
+         {label: _('Last Modified By'), field: 'last_modified_by',   valueType: 'user'},
+         {label: _('Creation Time'), field: 'creation_time',      valueType: 'date'},
+         {label: _('Created By'), field: 'created_by',         valueType: 'user'}
      ];
  };
  
@@@ -226,29 -218,46 +218,53 @@@ msgid_plural "Divisions
  msgstr[0] ""
  msgstr[1] ""
  
- #: js/ContractEditDialog.js:96
- msgid "Please use a decimal number here!"
+ #: js/ProductEditDialog.js:93 js/ProductGridPanel.js:121
+ msgid "Name"
  msgstr ""
  
- #: js/ContractEditDialog.js:149
- msgid "Contract Contact"
+ #: js/ProductEditDialog.js:99 js/ProductGridPanel.js:125
+ msgid "Price"
  msgstr ""
  
- #: js/ContractEditDialog.js:161
- msgid "Account Manager"
+ #: js/ProductEditDialog.js:106 js/ProductGridPanel.js:122
+ msgid "Manufacturer"
  msgstr ""
  
- #: js/ContractEditDialog.js:170
- msgid "Company"
+ #: js/ProductEditDialog.js:110 js/ProductGridPanel.js:123
+ msgid "Category"
  msgstr ""
  
- #: Controller/Contract.php:83
- msgid "The number you have tried to set is already in use!"
+ #: Model/Contract.php:107
+ msgid "Responsible"
+ msgstr ""
+ #: Model/Contract.php:108
+ msgid "Customer"
+ msgstr ""
+ #: Model/Contract.php:109
+ msgid "Partner"
+ msgstr ""
+ #: Setup/Initialize.php:34 Setup/Update/Release5.php:63
+ msgid "My Products"
+ msgstr ""
+ #: Setup/Initialize.php:35 Setup/Update/Release5.php:64
+ msgid "Products created by myself"
+ msgstr ""
+ #: Setup/Initialize.php:55 Setup/Update/Release5.php:84
+ msgid "My Contracts"
+ msgstr ""
+ #: Setup/Initialize.php:56 Setup/Update/Release5.php:85
+ msgid "Contracts created by myself"
  msgstr ""
 +
 +msgid "Lead Cost Center"
 +msgstr ""
 +
 +msgid "Time Account"
 +msgstr ""
 +
@@@ -393,56 -389,54 +389,66 @@@ msgstr "
  msgid "Update field:"
  msgstr ""
  
- #: js/TimeAccountBilledFilterModel.js:24
- msgid "Time Account - Billed"
+ #: js/Timetracker.js:25
+ msgid "New Timesheet"
  msgstr ""
  
- #: js/DurationSlider.js:94
- msgid "{0}"
+ #: Preference.php:64
+ msgid "Timesheets ODS export configuration"
  msgstr ""
  
- #: js/TimeAccountContractFilterModel.js:30
- msgid "Contract"
+ #: Preference.php:65
+ msgid "Use this configuration for the timesheet ODS export."
  msgstr ""
  
- #: js/TimeAccountContractFilterModel.js:32
- msgid "without contract"
+ #: Preference.php:116
+ msgid "default"
  msgstr ""
  
- #: js/Models.js:52
- msgid "timesheets list"
- msgid_plural "timesheets lists"
- msgstr[0] ""
- msgstr[1] ""
+ #: Setup/Initialize.php:33
+ msgid "My Timesheets today"
+ msgstr ""
  
- #: js/Models.js:87 js/Models.js:166
- msgid "Quick search"
+ #: Setup/Initialize.php:47
+ msgid "My Timesheets this week"
  msgstr ""
  
- #: js/Models.js:93 js/Models.js:172
- msgid "Last Modified Time"
+ #: Setup/Initialize.php:61
+ msgid "My Timesheets last week"
  msgstr ""
  
- #: js/Models.js:94 js/Models.js:173
- msgid "Last Modified By"
+ #: Setup/Initialize.php:75
+ msgid "My Timesheets this month"
  msgstr ""
  
- #: js/Models.js:95 js/Models.js:174
- msgid "Creation Time"
+ #: Setup/Initialize.php:89
+ msgid "My Timesheets last month"
  msgstr ""
  
- #: js/Models.js:96 js/Models.js:175
- msgid "Created By"
+ #: Setup/Initialize.php:112 Setup/Update/Release5.php:81
+ msgid "Timeaccounts to bill"
+ msgstr ""
+ #: Setup/Initialize.php:126 Setup/Update/Release5.php:95
+ msgid "Timeaccounts not yet billed"
+ msgstr ""
+ #: Setup/Initialize.php:141 Setup/Update/Release5.php:109
+ msgid "Timeaccounts already billed"
+ msgstr ""
+ #: Setup/setup.xml:4
+ msgid "Timetracker"
  msgstr ""
- msgstr ""
 +
 +#: js/Models.js:145
 +msgid "timeaccount list"
 +msgid_plural "timeaccount lists"
 +msgstr[0] ""
 +msgstr[1] ""
 +
 +msgid "Responsible person"
 +msgstr ""
 +
 +msgid "Cleared at"
++msgstr ""
  class Tinebase_Exception extends Exception
  {
      /**
 -    
 +     * the name of the application, this exception belongs to
 +     * 
 +     * @var string
 +     */
 +    protected $_appName = NULL;
 +    
 +    /**
 +     * the title of the Exception (may be shown in a dialog)
 +     * 
 +     * @var string
 +     */
 +    protected $_title = NULL;
 +    
 +    /**
 +     * the constructor
 +     * 
 +     * @param message[optional]
 +     * @param code[optional]
 +     * @param previous[optional]
 +     */
 +    public function __construct($message = null, $code = null, $previous = null)
 +    {
 +        if (! $this->_appName) {
 +            $c = explode('_', get_class($this));
 +            $this->_appName = $c[0];
 +        }
 +        
 +        if (! $this->_title) {
 +            $this->_title = 'Exception ({0})'; // _('Exception ({0})')
 +        }
 +        
 +        parent::__construct(($message ? $message : $this->message), $code, $previous);
 +    }
 +    
 +    /**
 +     * returns the name of the application, this exception belongs to
 +     * 
 +     * @return string
 +     */
 +    public function getAppName()
 +    {
 +        return $this->_appName;
 +    }
 +    
 +    /**
 +     * returns the title of this exception
 +     *
 +     * @return string
 +     */
 +    public function getTitle()
 +    {
 +        return $this->_title;
 +    }
++    
++    /**
+      * get exception trace as array (remove confidential information)
+      * 
+      * @param Exception $exception
+      * @return array
+      */
+     public static function getTraceAsArray(Exception $exception)
+     {
+         $trace = $exception->getTrace();
+         $traceArray = array();
+         
+         foreach($trace as $part) {
+             if (array_key_exists('file', $part)) {
+                 // don't send full paths to the client
+                 $part['file'] = self::_replaceBasePath($part['file']);
+             }
+             // unset args to make sure no passwords are shown
+             unset($part['args']);
+             $traceArray[] = $part;
+         }
+         
+         return $traceArray;
+     }
+     
+     /**
+      * replace base path in string
+      * 
+      * @param string|array $_string
+      * @return string
+      */
+     protected static function _replaceBasePath($_string)
+     {
+         $basePath = dirname(dirname(__FILE__));
+         return str_replace($basePath, '...', $_string);
+     }
+     
+     /**
+      * log exception (remove confidential information from trace)
+      * 
+      * @param Exception $exception
+      * @param boolean $suppressTrace
+      */
+     public static function log(Exception $exception, $suppressTrace = NULL)
+     {
+         Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . get_class($exception) . ' -> ' . $exception->getMessage());
+         
+         $suppressTrace = ($suppressTrace !== NULL) ? $suppressTrace : Tinebase_Core::getConfig()->suppressExceptionTraces === TRUE;
+         if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE) && ! $suppressTrace) {
+             $traceString = $exception->getTraceAsString();
+             $traceString = self::_replaceBasePath($traceString);
+             $traceString = self::_removeCredentials($traceString);
+              
+             Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' ' . $traceString);
+         }
+     }
+     
+     /**
+      * remove credentials/passwords from trace 
+      * 
+      * @param string $_traceString
+      * @return string
+      */
+     protected static function _removeCredentials($_traceString)
+     {
+         $passwordPatterns = array(
+             "/->login\('([^']*)', '[^']*'/",
+             "/->loginFromPost\('([^']*)', '[^']*'/",
+             "/->validate\('[^']*', '[^']*'/",
+             "/->authenticate\('[^']*', '[^']*'/",
+         );
+         $replacements = array(
+             "->login('$1', '********'",
+             "->loginFromPost('$1', '********'",
+             "->validate('$1', '********'",
+             "->authenticate('$1', '********'",
+         );
+         
+         return preg_replace($passwordPatterns, $replacements, $_traceString);
+     }
  }
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -249,18 -252,13 +252,21 @@@ class Tinebase_Server_Json implements T
          $exceptionData = method_exists($exception, 'toArray')? $exception->toArray() : array();
          $exceptionData['message'] = htmlentities($exception->getMessage(), ENT_COMPAT, 'UTF-8');
          $exceptionData['code']    = $exception->getCode();
-         if (Tinebase_Core::getConfig()->suppressExceptionTraces !== TRUE) {
-             $exceptionData['trace'] = $this->_getTraceAsArray($exception);
-             $this->_logExceptionTrace($exception);
 +        
 +        if ($exception instanceof Tinebase_Exception) {
 +            $exceptionData['appName'] = $exception->getAppName();
 +            $exceptionData['title'] = $exception->getTitle();
 +        }
 +        
 +        Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . get_class($exception) . ' -> ' . $exception->getMessage());
++        
+         $suppressTrace = Tinebase_Core::getConfig()->suppressExceptionTraces;
+         if ($suppressTrace !== TRUE) {
+             $exceptionData['trace'] = Tinebase_Exception::getTraceAsArray($exception);
          }
          
+         Tinebase_Exception::log($exception, $suppressTrace);
+         
          $server->fault($exceptionData['message'], $exceptionData['code'], $exceptionData);
          
          $response = $server->getResponse();
@@@ -469,18 -471,14 +472,18 @@@ Tine.widgets.relation.GenericPickerGrid
  
      /**
       * returns the type editors for each row in the grid
 -     * @param {} relation
 +     * 
 +     * @param {Object} config
 +     * @param {Tine.Tinebase.Application}
 +     * 
       * @return {}
       */
 -    getTypeEditor: function(config) {
 +    getTypeEditor: function(config, app) {
-         var data = [];
+         var data = [['', '']];
          Ext.each(config, function(c){
 -            data.push([c.type.toUpperCase(), c.text]);
 +            data.push([c.type.toUpperCase(), app.i18n._hidden(c.text)]);
          });
 +        
          return new Ext.form.ComboBox({
              store: new Ext.data.ArrayStore({
                  fields: ['id', 'value'],
              displayField: 'value',
              valueField: 'id',
              mode: 'local',
-             }
 +            constrainsConfig: config,
 +            listeners: {
 +                scope: this,
 +                select: this.onTypeChange
++            },
+             tpl: '<tpl for="."><div class="x-combo-list-item">{value}&nbsp;</div></tpl>'
          });
      },
  
@@@ -2757,6 -2757,3 +2757,6 @@@ msgid "
  "You are not allowed to delete this Container. Please define another "
  "container as the default addressbook for internal contacts!"
  msgstr "Es ist nicht erlaubt diesen Ordner zu löschen. Bitte definieren sie zuvor einen anderen Ordner für interne Kontakte!"
- msgstr "Ausnahmefehler ({0})"
 +
 +msgid "Exception ({0})"
++msgstr "Ausnahmefehler ({0})"
@@@ -359,45 -243,45 +359,49 @@@ class OpenDocument_Documen
              file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'meta.xml', $this->_meta);
              file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'settings.xml', $this->_settings);
              file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'META-INF/manifest.xml', $this->_manifest);
 -        }
 -        
 -        // ObjectReplacements
 -//        $images = $this->_document->xpath('//draw:image');
 -//        foreach($images as $image) {
 -//            $image_sxe = dom_import_simplexml($image);
 -//            $image_sxe->parentNode->removeChild($image_sxe);
 -//        }
 -//        
 -//        $images = $this->_document->xpath('//draw:image');
 -//        Tinebase_Core::getLogger()->err(print_r($images, TRUE));
 -        
 -        file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'content.xml', $this->_document->saveXML());
 -        file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'styles.xml', $this->_styles);
 -        
 -        $zip = new ZipArchive();
 -        $opened = $zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);
 -        if( $opened !== true ) {
 -            throw new Exception('could not open zip file');
 -        }
 -
 -        $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tempDir));
 -        
 -        foreach ($iterator as $fullFilename => $cur) {
 -            // the second parameter of the addFile function needs always the unix directory separator
 -            $localname = str_replace('\\', '/', substr($fullFilename, strlen($tempDir)+1));
              
 -            // exclude . and ..
 -            $localname_parts = pathinfo($localname);
 -            $localbasename = $localname_parts['basename'];
 -            if ($localbasename !== '.' && $localbasename !== '..') {
 -                $zip->addFile($fullFilename, $localname);
 +            file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'content.xml', $this->_document->saveXML());
 +            file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'styles.xml', $this->_styles);
 +            
 +            $zip = new ZipArchive();
 +            $opened = $zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);
 +            
 +            if( $opened !== true ) {
 +                throw new Exception('could not open zip file');
 +            }
 +            
 +            $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tempDir));
 +            
 +            foreach ($iterator as $fullFilename => $cur) {
 +                // the second parameter of the addFile function needs always the unix directory separator
 +                $localname = str_replace('\\', '/', substr($fullFilename, strlen($tempDir)+1));
-                 if ($localname !== 'mimetype' && $localname !== '.' && $localname !== '..') {
++                
++                // exclude . and ..
++                $localname_parts = pathinfo($localname);
++                $localbasename = $localname_parts['basename'];
++                if ($localbasename !== 'mimetype' && $localbasename !== '.' && $localbasename !== '..') {
 +                    $zip->addFile($fullFilename, $localname);
 +                }
 +            }
 +    
 +            $zip->close();
 +            
 +            // delete files / remove dir
 +            removeDir($tempDir);
 +            
 +            
 +        } else {
 +            $templateZip = new ZipArchive();
 +            if ($templateZip->open($this->_templateFile) === TRUE) {
 +                $templateZip->close();
 +                
 +                copy($this->_templateFile, $filename);
 +                
 +                $templateZip->open($filename);
 +                $templateZip->addFromString('content.xml', $this->_document->saveXML());
 +                $templateZip->close();
              }
          }
 -
 -        $zip->close();
 -        
 -        // delete files / remove dir
 -        removeDir($tempDir);
          
          return $filename;
      }
              }
              $dom_sxe = dom_import_simplexml($newChild);
              $newStyle = $domStyles->ownerDocument->importNode($dom_sxe, true);
 -            $domStyles->appendChild($newStyle);        
 +            $domStyles->appendChild($newStyle);
          }
 -        
 -        #if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $styles[0]->generateXML());
      }
- }
+ }