00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 from PyQt4.QtCore import *
00031 from PyQt4.QtGui import *
00032 from PyQt4.uic import *
00033 
00034 import gettext
00035 from Koo.Common import Common
00036 from Koo.Common import Numeric
00037 from Koo.Common import OpenOffice
00038 from Koo.Screen.ViewQueue import *
00039 
00040 from Koo import Rpc
00041 
00042 import types
00043 import os
00044 import codecs
00045 
00046 from ImportExportCommon import *
00047 
00048 def exportHtml(fname, fields, result, writeTitle):
00049         QApplication.setOverrideCursor( Qt.WaitCursor )
00050         try:
00051                 f = codecs.open( fname, 'wb+', 'utf8' )
00052         except IOError, (errno, strerror):
00053                 QApplication.restoreOverrideCursor()
00054                 QMessageBox.warning( None, _('Error'), _("Operation failed !\nI/O error (%s)") % (errno))
00055                 return
00056         try:
00057                 f.write( '<html>' )
00058                 f.write( '<head><title>' + _('OpenERP exported information') + '</title></head>' )
00059                 f.write( '<table>' )
00060                 if writeTitle:
00061                         f.write( '<tr>' )
00062                         for x in fields:
00063                                 x = unicode(x)
00064                                 f.write('<th>%s</th>' % x)
00065                         f.write( '</tr>' )
00066                 for x in result:
00067                         row = []
00068                         for y in x:
00069                                 y = unicode(y)
00070                                 y = y.replace('\n','<br/>').replace('\t',' ')
00071                                 y = y.replace('<','<').replace('>','>').replace('&','&')
00072                                 row.append(y)
00073                         f.write( '<tr>' )
00074                         f.write( '<td>%s</td>' % ( '</td><td>'.join( row ) ) )
00075                         f.write( '</tr>' )
00076                 QApplication.restoreOverrideCursor()
00077                 QMessageBox.information( None, _('Information'), _('%s record(s) saved!') % (str(len(result))) )
00078         except IOError, (errno, strerror):
00079                 QApplication.restoreOverrideCursor()
00080                 QMessageBox.warning( None, _('Error'), _("Operation failed !\nI/O error (%s)") % (errno))
00081         finally:
00082                 f.close()
00083 
00084 def textToCsv(text):
00085         return '"%s"' % text.replace('\n',' ').replace('\t', ' ').replace('"','\\"')
00086 
00087 def exportCsv(fname, fields, result, writeTitle):
00088         QApplication.setOverrideCursor( Qt.WaitCursor )
00089         try:
00090                 fp = codecs.open( fname, 'wb+', 'utf8' )
00091         except IOError, (errno, strerror):
00092                 QApplication.restoreOverrideCursor()
00093                 QMessageBox.warning( None, _('Data Export'), _("Operation failed !\nI/O error (%s)") % (errno))
00094                 return
00095         try:
00096                 if writeTitle:
00097                         fp.write( ','.join( [textToCsv(x) for x in fields] ) + '\n' )
00098                 for data in result:
00099                         row = []
00100                         for d in data:
00101                                 if isinstance(d, str):
00102                                         row.append( textToCsv(d) )
00103                                 elif not isinstance( d, unicode ):
00104                                         row.append( textToCsv(unicode(d)) )
00105                                 else:
00106                                         row.append( textToCsv(d) )
00107                         fp.write( ','.join( row ) + '\n' )
00108                 QApplication.restoreOverrideCursor()
00109                 QMessageBox.information( None, _('Data Export'), _('%s record(s) saved!') % (str(len(result))) )
00110         except IOError, (errno, strerror):
00111                 QApplication.restoreOverrideCursor()
00112                 QMessageBox.warning( None, _('Data Export'), _("Operation failed !\nI/O error (%s)") % (errno))
00113         except Exception, e:
00114                 QApplication.restoreOverrideCursor()
00115                 QMessageBox.warning( None, _('Data Export'), _("Error exporting data:\n%s") % unicode(e.args) )
00116         finally:
00117                 fp.close()
00118 
00119 
00120 
00121 def convertTypes(data, fieldsType):
00122         for a in data:
00123                 for b in range(len(a)):
00124                         if type(a[b]) == type(''):
00125                                 a[b]=a[b].decode('utf-8','replace')
00126                         elif type(a[b]) == type([]):
00127                                 if len(a[b])==2:
00128                                         a[b] = a[b][1].decode('utf-8','replace')
00129                                 else:
00130                                         a[b] = ''
00131                         if fieldsType[b] in ('float', 'integer'):
00132                                 if Numeric.isNumeric( a[b] ):
00133                                         a[b] = float( a[b] )
00134         return data
00135 
00136 def openExcel(fields, fieldsType, result, writeTitle):
00137         QApplication.setOverrideCursor( Qt.WaitCursor )
00138         try:
00139                 from win32com.client import Dispatch
00140                 application = Dispatch("Excel.Application")
00141                 application.Workbooks.Add()
00142 
00143                 sheet = application.ActiveSheet
00144                 row = 1
00145                 if writeTitle:
00146                         for col in range(len(fields)):
00147                                 sheet.Cells( row, col + 1 ).Value = fields[col]
00148                         row += 1
00149 
00150                 result = convertTypes( result, fieldsType )
00151                 sheet.Range(sheet.Cells(row, 1), sheet.Cells(row + len(result)-1, len(fields))).Value = result
00152                 
00153                 application.Visible = 1
00154                 QApplication.restoreOverrideCursor()
00155         except Exception, e:
00156                 QApplication.restoreOverrideCursor()
00157                 QMessageBox.warning(None, _('Error'), _('Error opening Excel:\n%s') % unicode(e.args) )
00158 
00159 
00160 
00161 def openOpenOffice(fields, fieldsType, result, writeTitle):
00162         QApplication.setOverrideCursor( Qt.WaitCursor )
00163         try:
00164                 import time
00165 
00166                 OpenOffice.OpenOffice.start()
00167 
00168                 for i in range(30):
00169                         ooo = OpenOffice.OpenOffice()
00170                         if ooo and ooo.desktop:
00171                                 break
00172                         time.sleep(1)
00173                 doc = ooo.desktop.loadComponentFromURL("private:factory/scalc",'_blank',0,())
00174                 sheet = doc.CurrentController.ActiveSheet
00175 
00176                 row = 0
00177                 if writeTitle:
00178                         for col in xrange(len(fields)):
00179                                 cell = sheet.getCellByPosition(col, row)
00180                                 cell.String = fields[col]
00181                         row += 1
00182 
00183                 result = convertTypes( result, fieldsType )
00184                 result = tuple( [tuple(x) for x in result] )
00185 
00186                 cellrange = sheet.getCellRangeByPosition(0, row, len(fields) - 1, row + len(result) - 1)
00187                 cellrange.setDataArray(result)
00188                 QApplication.restoreOverrideCursor()
00189         except Exception, e:
00190                 QApplication.restoreOverrideCursor()
00191                 QMessageBox.warning(None, _('Error'), _('Error Opening OpenOffice.org:\n%s') % unicode(e.args) )
00192 
00193 def exportData(ids, model, fields, prefix=''):
00194         data = Rpc.session.execute('/object', 'execute', model, 'export_data', ids, fields, Rpc.session.context)
00195         
00196         if isinstance(data, dict) and 'datas' in data:
00197                 data = data['datas']
00198         return data
00199 
00200 (ExportDialogUi, ExportDialogBase) = loadUiType( Common.uiPath('win_export.ui') )
00201 
00202 class ExportDialog( QDialog, ExportDialogUi ):
00203         exports = {}
00204 
00205         def __init__(self, parent=None):
00206                 QDialog.__init__(self, parent)
00207                 ExportDialogUi.__init__(self)
00208                 self.setupUi( self )
00209 
00210                 self.ids = []
00211                 self.model = None
00212                 self.fields = None
00213                 self.connect( self.pushAccept, SIGNAL('clicked()'), self.export )
00214                 self.connect( self.pushCancel, SIGNAL('clicked()'), self.reject )
00215                 self.connect( self.pushAdd, SIGNAL('clicked()'), self.add )
00216                 self.connect( self.pushRemove, SIGNAL('clicked()'), self.remove )
00217                 self.connect( self.pushRemoveAll, SIGNAL('clicked()'), self.removeAll )
00218                 self.connect( self.pushSave, SIGNAL('clicked()'), self.save )
00219                 self.connect( self.pushRemoveExport, SIGNAL('clicked()'), self.removeExport )
00220                 self.connect( self.uiPredefined, SIGNAL('activated(const QModelIndex&)'), self.loadCurrentStored )
00221 
00222         def setModel( self, model ):
00223                 self.model = model
00224 
00225         def setIds( self, ids ):
00226                 self.ids = ids
00227 
00228         def setup( self, viewTypes, viewIds ):
00229                 self.viewTypes = viewTypes
00230                 self.viewIds = viewIds
00231                 QTimer.singleShot( 0, self.initGui )
00232 
00233         def initGui(self):
00234                 QApplication.setOverrideCursor( Qt.WaitCursor )
00235                 
00236                 try:
00237                         self.fields = {}
00238                         queue = ViewQueue()
00239                         queue.setup( self.viewTypes, self.viewIds )
00240                         while not queue.isEmpty():
00241                                 id, type = queue.next()
00242                                 view = Rpc.session.execute('/object', 'execute', self.model, 'fields_view_get', id, type, Rpc.session.context)
00243                                 self.fields.update( view['fields'] )
00244                 except Rpc.RpcException, e:
00245                         QApplication.restoreOverrideCursor()
00246                         return
00247 
00248                 for key, export in ExportDialog.exports.iteritems():
00249                         self.uiFormat.addItem( export['label'], QVariant( key ) )       
00250 
00251                 self.fieldsInfo = {}
00252                 self.allModel = FieldsModel()
00253                 self.allModel.load( self.fields, self.fieldsInfo )
00254                 self.uiAllFields.setModel( self.allModel )
00255                 self.uiAllFields.sortByColumn( 0, Qt.AscendingOrder )
00256 
00257                 self.selectedModel = FieldsModel()
00258                 self.uiSelectedFields.setModel( self.selectedModel )
00259 
00260                 self.storedModel = StoredExportsModel()
00261                 self.storedModel.load( self.model, self.fieldsInfo )
00262                 self.uiPredefined.setModel( self.storedModel )
00263                 self.uiPredefined.hideColumn(0)
00264                 self.uiPredefined.hideColumn(1)
00265 
00266                 QApplication.restoreOverrideCursor()
00267 
00268         @staticmethod
00269         def registerExport(key, label, requiresFileName, function):
00270                 ExportDialog.exports[ key ] = {
00271                         'label': label,
00272                         'requiresFileName': requiresFileName,
00273                         'function': function
00274                 }
00275 
00276         @staticmethod
00277         def unregisterExport(key):
00278                 del ExportDialog.exports[ key ]
00279 
00280         def removeExport(self):
00281                 idx = self.uiPredefined.selectionModel().selectedRows(1)
00282                 if len(idx) != 1:
00283                         return
00284                 idx = idx[0]
00285                 id = int( unicode( self.storedModel.itemFromIndex( idx ).text() ) )
00286                 ir_export = Rpc.RpcProxy('ir.exports')
00287                 ir_export.unlink([id])
00288                 self.storedModel.load( self.model, self.fieldsInfo )
00289 
00290         def loadCurrentStored(self):
00291                 idx = self.uiPredefined.selectionModel().selectedRows(0)
00292                 if len(idx) != 1:
00293                         return
00294                 idx = idx[0]
00295                 fields = unicode( self.storedModel.itemFromIndex( idx ).text() )
00296                 fields = fields.split(', ') 
00297                 if self.selectedModel.rowCount() > 0:
00298                         self.selectedModel.removeRows(0, self.selectedModel.rowCount() )
00299                 for x in fields:
00300                         newItem = QStandardItem()
00301                         newItem.setText( unicode( self.fieldsInfo[x]['string'] ) )
00302                         newItem.setData( QVariant(x) )
00303                         self.selectedModel.appendRow( newItem )
00304 
00305         def export(self):
00306                 fields = []
00307                 fieldTitles = []
00308                 for x in range(0, self.selectedModel.rowCount() ):
00309                         fields.append( unicode( self.selectedModel.item( x ).data().toString() ) )
00310                         fieldTitles.append( unicode( self.selectedModel.item( x ).text() ) )
00311                 action = unicode( self.uiFormat.itemData(self.uiFormat.currentIndex()).toString() )
00312                 result = exportData(self.ids, self.model, fields)
00313                 export = ExportDialog.exports[action]
00314                 if export['requiresFileName']:
00315                         fileName = unicode( QFileDialog.getSaveFileName( self, _('Export Data') ) )
00316                         export['function'](fileName, fieldTitles, result, self.uiAddFieldNames.isChecked() )
00317                 else:
00318                         fieldsType = [self.fieldsInfo[x]['type'] for x in fields]
00319                         export['function'](fieldTitles, fieldsType, result, self.uiAddFieldNames.isChecked() )
00320 
00321         def add(self):
00322                 idx = self.uiAllFields.selectionModel().selectedRows()
00323                 if len(idx) != 1:
00324                         return 
00325                 idx = idx[0]
00326                 item = self.allModel.itemFromIndex( idx )
00327                 newItem = QStandardItem( item )
00328                 newItem.setText( self.fullPathText(item) )
00329                 newItem.setData( QVariant(self.fullPathData(item)) )
00330                 self.selectedModel.appendRow( newItem )
00331 
00332         def remove(self):
00333                 idx = self.uiSelectedFields.selectedIndexes()
00334                 if len(idx) != 1:
00335                         return
00336                 idx = idx[0]
00337                 self.selectedModel.removeRows( idx.row(), 1 )
00338 
00339         def removeAll(self):
00340                 if self.selectedModel.rowCount() > 0:
00341                         self.selectedModel.removeRows(0, self.selectedModel.rowCount())
00342 
00343         def fullPathText(self, item):
00344                 path = unicode( item.text() )
00345                 while item.parent() != None:
00346                         item = item.parent()
00347                         path = item.text() + "/" + path
00348                 return path
00349         
00350         def fullPathData(self, item):
00351                 path = unicode( item.data().toString() )
00352                 while item.parent() != None:
00353                         item = item.parent()
00354                         path = item.data().toString() + "/" + path
00355                 return path
00356 
00357         def save(self):
00358                 name, ok = QInputDialog.getText(self, '', _('What is the name of this export?'))
00359                 if not ok:
00360                         return
00361                 ir_export = Rpc.RpcProxy('ir.exports')
00362                 fields = []
00363                 for x in range(0, self.selectedModel.rowCount() ):
00364                         fields.append( unicode( self.selectedModel.item(x).data().toString() ) )
00365 
00366                 ir_export.create({
00367                         'name' : unicode(name), 
00368                         'resource' : self.model,
00369                         'export_fields' : [(0, 0, {'name' : f}) for f in fields]
00370                 })
00371                 self.storedModel.load( self.model, self.fieldsInfo )
00372 
00373 
00374 
00375 if OpenOffice.isOpenOfficeAvailable:
00376         ExportDialog.registerExport('openoffice', _('Open with OpenOffice.org'), False, openOpenOffice)
00377 
00378 if os.name == 'nt':
00379         try:
00380                 from win32com.client import Dispatch
00381                 application = Dispatch("Excel.Application")
00382                 ExportDialog.registerExport('excel', _('Open with Excel'), False, openExcel)
00383         except:
00384                 pass
00385 ExportDialog.registerExport('csv', _('Save as CSV'), True, exportCsv)
00386 ExportDialog.registerExport('html', _('Save as HTML'), True, exportHtml)
00387 
00388 
00389 
00390 
00391 class StoredExportsModel( QStandardItemModel ):
00392         def __init__(self):
00393                 QStandardItemModel.__init__(self)
00394                 self.rootItem = self.invisibleRootItem()
00395                 self.setColumnCount( 4 )
00396                 self.setHeaderData( 0, Qt.Horizontal, QVariant('Field list (internal names)') )
00397                 self.setHeaderData( 1, Qt.Horizontal, QVariant('Export id') )
00398                 self.setHeaderData( 2, Qt.Horizontal, QVariant( _('Export name') ) )
00399                 self.setHeaderData( 3, Qt.Horizontal, QVariant( _('Exported fields') ) )
00400 
00401         def load(self, model, fieldsInfo):
00402                 if self.rowCount() > 0:
00403                         self.removeRows(0, self.rowCount())
00404                 ir_export = Rpc.RpcProxy('ir.exports')
00405                 ir_export_line = Rpc.RpcProxy('ir.exports.line')
00406                 export_ids = ir_export.search([('resource', '=', model)])
00407                 for export in ir_export.read(export_ids):
00408                         fields = ir_export_line.read(export['export_fields'])
00409 
00410                         allFound = True
00411                         for f in fields:
00412                                 if not f['name'] in fieldsInfo:
00413                                         allFound = False
00414                                         break
00415                         if not allFound:
00416                                 continue
00417 
00418                         items = [ QStandardItem( ', '.join([f['name'] for f in fields]) ), QStandardItem( str(export['id']) ), QStandardItem( export['name'] ), QStandardItem( ', '.join( [fieldsInfo[f['name']]['string'] for f in fields] ) ) ]
00419                         self.rootItem.appendRow( items )