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 )