| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | # vim: ts=4:sw=4 |
|---|
| 3 | # This file is part of LOME. |
|---|
| 4 | # |
|---|
| 5 | # LOME is free software: you can redistribute it and/or modify |
|---|
| 6 | # it under the terms of the GNU General Public License as published by |
|---|
| 7 | # the Free Software Foundation, either version 3 of the License, or |
|---|
| 8 | # (at your option) any later version. |
|---|
| 9 | # |
|---|
| 10 | # LOME is distributed in the hope that it will be useful, |
|---|
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | # GNU General Public License for more details. |
|---|
| 14 | # |
|---|
| 15 | # You should have received a copy of the GNU General Public License |
|---|
| 16 | # along with LOME. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | # |
|---|
| 18 | |
|---|
| 19 | # @ Main LOME entry |
|---|
| 20 | # Launch LOME |
|---|
| 21 | import sys,os,logging,traceback |
|---|
| 22 | sys.path.append(os.path.join(sys.path[0],'common')) |
|---|
| 23 | sys.path.append(os.path.join(sys.path[0],'common','misabstractlayer')) |
|---|
| 24 | sys.path.append(os.path.join(sys.path[0],'common','misabstractlayer', 'tacview')) |
|---|
| 25 | from PyQt4.QtGui import * |
|---|
| 26 | from debug import * |
|---|
| 27 | from constants import * |
|---|
| 28 | from xml.dom.minidom import Document |
|---|
| 29 | from xml.dom import minidom |
|---|
| 30 | from loimport import * |
|---|
| 31 | from loexport import * |
|---|
| 32 | from taclog import * |
|---|
| 33 | from application import * |
|---|
| 34 | g_under_windows = True |
|---|
| 35 | try: |
|---|
| 36 | import win32com.client |
|---|
| 37 | import _winreg |
|---|
| 38 | except: |
|---|
| 39 | g_under_windows = False |
|---|
| 40 | import glob |
|---|
| 41 | |
|---|
| 42 | ############################# |
|---|
| 43 | MT_MIS_PATH = "C:\Program Files\Ubisoft\Eagle Dynamics\Lock On\Missions\LAN_X" |
|---|
| 44 | MT_DEB_PATH = "debrief" |
|---|
| 45 | ############################# |
|---|
| 46 | g_object = None |
|---|
| 47 | |
|---|
| 48 | try: |
|---|
| 49 | import logging.config |
|---|
| 50 | # Set logging config |
|---|
| 51 | logging.config.fileConfig('logging.conf') |
|---|
| 52 | except: |
|---|
| 53 | # Set logging config |
|---|
| 54 | logging.basicConfig(level=logging.WARNING, format='%(name)s: %(message)s' |
|---|
| 55 | ,filename='lomerge.log', filemode='w' |
|---|
| 56 | ) |
|---|
| 57 | |
|---|
| 58 | class MergeTool( QWidget ): |
|---|
| 59 | #----------------------------------------------------------------------- |
|---|
| 60 | def __init__(self, pathname): |
|---|
| 61 | QWidget.__init__(self, None) |
|---|
| 62 | self.vlay = QVBoxLayout(self) |
|---|
| 63 | |
|---|
| 64 | self.listlay = QHBoxLayout() |
|---|
| 65 | self.vlay.addLayout( self.listlay ) |
|---|
| 66 | |
|---|
| 67 | self.deb_list = QListView() |
|---|
| 68 | self.listlay.addWidget( self.deb_list ) |
|---|
| 69 | |
|---|
| 70 | self.mis_list = QListView() |
|---|
| 71 | self.listlay.addWidget( self.mis_list ) |
|---|
| 72 | self.connect( self.mis_list, SIGNAL("doubleClicked( const QModelIndex & )"), self.on_mis_dbl_click ) |
|---|
| 73 | |
|---|
| 74 | self.vlay.addWidget( QLabel("Made by DArt - http://lotatc.dartsite.org") ) |
|---|
| 75 | |
|---|
| 76 | self.button_merge = QPushButton("Merge files") |
|---|
| 77 | self.vlay.addWidget( self.button_merge ) |
|---|
| 78 | self.connect( self.button_merge, SIGNAL("clicked()"), self.merge_files_dlg ) |
|---|
| 79 | |
|---|
| 80 | self.button_stats = QPushButton("Statistiques") |
|---|
| 81 | self.vlay.addWidget( self.button_stats ) |
|---|
| 82 | self.connect( self.button_stats, SIGNAL("clicked()"), self.show_stats ) |
|---|
| 83 | |
|---|
| 84 | self.work_path = pathname |
|---|
| 85 | self.application = Application() |
|---|
| 86 | |
|---|
| 87 | self.first_mission = None |
|---|
| 88 | |
|---|
| 89 | self.load_lo() |
|---|
| 90 | self.list_mission() |
|---|
| 91 | self.list_debrief() |
|---|
| 92 | #----------------------------------------------------------------------- |
|---|
| 93 | def on_mis_dbl_click ( self, modindex ): |
|---|
| 94 | item = self.mis_model.itemFromIndex( modindex ) |
|---|
| 95 | if item: |
|---|
| 96 | if self.first_mission: |
|---|
| 97 | self.first_mission.setBackground( QBrush() ) |
|---|
| 98 | self.first_mission = item |
|---|
| 99 | self.first_mission.setCheckState( Qt.Checked ) |
|---|
| 100 | self.first_mission.setBackground( QColor(0,255,255) ) |
|---|
| 101 | #----------------------------------------------------------------------- |
|---|
| 102 | def load_lo( self ): |
|---|
| 103 | if g_under_windows: |
|---|
| 104 | handle = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE , u"SOFTWARE\\Ubisoft\\Eagle Dynamics\\Lock On") |
|---|
| 105 | if handle: |
|---|
| 106 | self.lopath, dummytype = _winreg.QueryValueEx(handle, u"Path") |
|---|
| 107 | # win32com.client.gencache.EnsureModule('{9E54695B-336B-4B3B-BBA9-0ABD36153FF3}', 0, 1, 0) |
|---|
| 108 | self.loapp = win32com.client.Dispatch("LockOn.MOM.Application2.1") |
|---|
| 109 | #self.loapp.HandBook.Load(self.lopath+"\\ME\\MEInit.xml") |
|---|
| 110 | self.loapp.HandBook.Load(self.work_path+"\\LANX_meinit.xml") |
|---|
| 111 | self.loImport = LOImport(self.loapp) |
|---|
| 112 | |
|---|
| 113 | #- Load handbook |
|---|
| 114 | myfile=os.path.join(self.work_path,"lome","handbook.lome") |
|---|
| 115 | res = self.application.load_handbook(myfile) |
|---|
| 116 | #----------------------------------------------------------------------- |
|---|
| 117 | def list_mission( self ): |
|---|
| 118 | files = glob.glob(os.path.join(MT_MIS_PATH, "*.mis")) |
|---|
| 119 | |
|---|
| 120 | self.mis_model = QStandardItemModel(len(files),1) |
|---|
| 121 | i = 0 |
|---|
| 122 | for f in files: |
|---|
| 123 | item = QStandardItem(f.replace(MT_MIS_PATH,"")[1:]) |
|---|
| 124 | item.setCheckable( True ) |
|---|
| 125 | item.setEditable( False ) |
|---|
| 126 | item.setCheckState( Qt.Checked ) |
|---|
| 127 | self.mis_model.setItem(i,0, item) |
|---|
| 128 | i += 1 |
|---|
| 129 | if not self.first_mission: |
|---|
| 130 | self.first_mission = item |
|---|
| 131 | self.first_mission.setBackground( QColor(0,255,255) ) |
|---|
| 132 | |
|---|
| 133 | self.mis_model.sort(0) |
|---|
| 134 | self.mis_list.setModel( self.mis_model ) |
|---|
| 135 | #----------------------------------------------------------------------- |
|---|
| 136 | def list_debrief( self ): |
|---|
| 137 | files = glob.glob(os.path.join(MT_DEB_PATH, "*.xml")) |
|---|
| 138 | |
|---|
| 139 | self.deb_model = QStandardItemModel(len(files),1) |
|---|
| 140 | i = 0 |
|---|
| 141 | for f in files: |
|---|
| 142 | item = QStandardItem(f.replace(MT_DEB_PATH,"")[1:]) |
|---|
| 143 | item.setCheckable( True ) |
|---|
| 144 | item.setEditable( False ) |
|---|
| 145 | # item.setCheckState( Qt.Checked ) |
|---|
| 146 | self.deb_model.setItem(i,0, item) |
|---|
| 147 | i += 1 |
|---|
| 148 | |
|---|
| 149 | self.deb_model.sort(0) |
|---|
| 150 | self.deb_list.setModel( self.deb_model ) |
|---|
| 151 | #----------------------------------------------------------------------- |
|---|
| 152 | def show_stats( self ): |
|---|
| 153 | cur_mis = None |
|---|
| 154 | killed = {"Allies":{},"Enemies":{}} |
|---|
| 155 | stocks = {"Allies":[]} |
|---|
| 156 | txt = "" |
|---|
| 157 | #- compute killed unit first |
|---|
| 158 | for i in range(0,self.deb_model.rowCount()): |
|---|
| 159 | it = self.deb_model.item(i) |
|---|
| 160 | if it.checkState() == Qt.Checked: |
|---|
| 161 | it_txt = os.path.join(MT_DEB_PATH,qstring2string( it.text() )) |
|---|
| 162 | print "Load debrief:", it_txt |
|---|
| 163 | fd = open(it_txt, 'r') |
|---|
| 164 | buffer = fd.read() |
|---|
| 165 | fd.close() |
|---|
| 166 | dom = None |
|---|
| 167 | try: |
|---|
| 168 | dom = minidom.parseString(buffer) |
|---|
| 169 | except: |
|---|
| 170 | exceptionType, exceptionValue, exceptionTraceback = sys.exc_info() |
|---|
| 171 | msg_a = traceback.format_exception(exceptionType, exceptionValue, exceptionTraceback) |
|---|
| 172 | msg = "" |
|---|
| 173 | for m in msg_a: |
|---|
| 174 | msg += m |
|---|
| 175 | print "PARSE ERROR:",msg |
|---|
| 176 | continue |
|---|
| 177 | if dom: |
|---|
| 178 | domexpl = DOMExplorer( dom ) |
|---|
| 179 | briefings = domexpl.get_all_elements("TacviewDebriefing") |
|---|
| 180 | taclog = TacLog( domexpl, briefings[0] ) |
|---|
| 181 | taclog.analyse() |
|---|
| 182 | for k,v in killed.iteritems(): |
|---|
| 183 | units = taclog.get_all_units_killed(k) |
|---|
| 184 | for u in units: |
|---|
| 185 | if not v.has_key( u[0] ): |
|---|
| 186 | v[u[0]] = {} |
|---|
| 187 | if not v[u[0]].has_key( u[1] ): |
|---|
| 188 | v[u[0]][u[1]] = 0 |
|---|
| 189 | v[u[0]][u[1]] += 1 |
|---|
| 190 | if stocks.has_key( k ): |
|---|
| 191 | stocks[k] += taclog.get_stocked_used(k) |
|---|
| 192 | for k,v in killed.iteritems(): |
|---|
| 193 | txt += "<strong><u>Coalition %s</u></strong><br />"%k |
|---|
| 194 | for u_n, u_v in v.iteritems(): |
|---|
| 195 | txt += "<strong>Unit: %s</strong><ul>"%u_n |
|---|
| 196 | for p_n, p_v in u_v.iteritems(): |
|---|
| 197 | txt += "<li>%s : %d </li>"%(p_n, p_v) |
|---|
| 198 | txt += "</ul>" |
|---|
| 199 | if stocks.has_key(k): |
|---|
| 200 | v = stocks[k] |
|---|
| 201 | for a in v: |
|---|
| 202 | txt += "<li>%s %s</li>"%(len(a[0]), a[1]) |
|---|
| 203 | txt += "</ul>" |
|---|
| 204 | txt += "__________________________________<br />" |
|---|
| 205 | dialog = QDialog(self) |
|---|
| 206 | |
|---|
| 207 | vbox = QVBoxLayout(dialog) |
|---|
| 208 | |
|---|
| 209 | w = QTextEdit( txt ) |
|---|
| 210 | vbox.addWidget( w ) |
|---|
| 211 | |
|---|
| 212 | |
|---|
| 213 | dialog.exec_() |
|---|
| 214 | #----------------------------------------------------------------------- |
|---|
| 215 | def merge_files_dlg( self ): |
|---|
| 216 | dia = QDialog(self) |
|---|
| 217 | vlay = QVBoxLayout(dia) |
|---|
| 218 | |
|---|
| 219 | dico = {} |
|---|
| 220 | |
|---|
| 221 | for i in range(0,self.mis_model.rowCount()): |
|---|
| 222 | it = self.mis_model.item(i) |
|---|
| 223 | if it.checkState() == Qt.Checked and it != self.first_mission: |
|---|
| 224 | listlay = QHBoxLayout() |
|---|
| 225 | vlay.addLayout( listlay ) |
|---|
| 226 | |
|---|
| 227 | txt = qstring2string( it.text() ) |
|---|
| 228 | listlay.addWidget( QLabel( it.text() ) ) |
|---|
| 229 | spin = QSpinBox() |
|---|
| 230 | spin.setRange( 1, 20 ) |
|---|
| 231 | spin.setValue( 1 ) |
|---|
| 232 | listlay.addWidget( spin ) |
|---|
| 233 | chx = QCheckBox("Random") |
|---|
| 234 | chx.setChecked( False ) |
|---|
| 235 | listlay.addWidget( chx ) |
|---|
| 236 | |
|---|
| 237 | dico[txt] = [spin, chx] |
|---|
| 238 | |
|---|
| 239 | okBtn = QPushButton( "Ok" ) |
|---|
| 240 | dia.connect( okBtn, SIGNAL("clicked()"), dia.accept ) |
|---|
| 241 | vlay.addWidget(okBtn) |
|---|
| 242 | |
|---|
| 243 | if dia.exec_() == QDialog.Accepted: |
|---|
| 244 | self.merge_files(dico) |
|---|
| 245 | #----------------------------------------------------------------------- |
|---|
| 246 | def merge_files( self, dico ): |
|---|
| 247 | cur_mis = None |
|---|
| 248 | killed = {"Allies":[], "Enemies":[]} |
|---|
| 249 | #- compute killed unit first |
|---|
| 250 | for i in range(0,self.deb_model.rowCount()): |
|---|
| 251 | it = self.deb_model.item(i) |
|---|
| 252 | if it.checkState() == Qt.Checked: |
|---|
| 253 | it_txt = os.path.join(MT_DEB_PATH,qstring2string( it.text() )) |
|---|
| 254 | print "Load debrief:", it_txt |
|---|
| 255 | fd = open(it_txt, 'r') |
|---|
| 256 | buffer = fd.read() |
|---|
| 257 | fd.close() |
|---|
| 258 | dom = None |
|---|
| 259 | try: |
|---|
| 260 | dom = minidom.parseString(buffer) |
|---|
| 261 | except: |
|---|
| 262 | exceptionType, exceptionValue, exceptionTraceback = sys.exc_info() |
|---|
| 263 | msg_a = traceback.format_exception(exceptionType, exceptionValue, exceptionTraceback) |
|---|
| 264 | msg = "" |
|---|
| 265 | for m in msg_a: |
|---|
| 266 | msg += m |
|---|
| 267 | print "PARSE ERROR:",msg |
|---|
| 268 | continue |
|---|
| 269 | if dom: |
|---|
| 270 | domexpl = DOMExplorer( dom ) |
|---|
| 271 | briefings = domexpl.get_all_elements("TacviewDebriefing") |
|---|
| 272 | taclog = TacLog( domexpl, briefings[0] ) |
|---|
| 273 | taclog.analyse() |
|---|
| 274 | for k,v in killed.iteritems(): |
|---|
| 275 | v += taclog.get_all_units_killed(k) |
|---|
| 276 | |
|---|
| 277 | #- merge files now |
|---|
| 278 | cur_mission = None |
|---|
| 279 | for i in range(0,self.mis_model.rowCount()): |
|---|
| 280 | it = self.mis_model.item(i) |
|---|
| 281 | if it.checkState() == Qt.Checked and it != self.first_mission: |
|---|
| 282 | it_txt = os.path.join(MT_MIS_PATH, qstring2string( it.text() ) ) |
|---|
| 283 | domerge = True |
|---|
| 284 | for k in killed: |
|---|
| 285 | if k in it_txt: |
|---|
| 286 | domerge = False |
|---|
| 287 | |
|---|
| 288 | if domerge: |
|---|
| 289 | print "Merge:", it_txt, cur_mis |
|---|
| 290 | if g_under_windows: |
|---|
| 291 | if not cur_mis: |
|---|
| 292 | import shutil |
|---|
| 293 | first_txt = os.path.join(MT_MIS_PATH, qstring2string( self.first_mission.text() ) ) |
|---|
| 294 | print first_txt |
|---|
| 295 | shutil.copy(first_txt, "output.mis" ) |
|---|
| 296 | cur_mis = "output.mis" |
|---|
| 297 | cur_mission, dummy = self.loImport.GetMission(cur_mis, self.application.handbook) |
|---|
| 298 | cur_mission = self.loImport.MergeMissions( cur_mission, it_txt, self.application.handbook, dico[qstring2string( it.text() )][0].value(), dico[qstring2string( it.text() )][1].isChecked() ) |
|---|
| 299 | # Save to |
|---|
| 300 | export = LOExport(self.loapp) |
|---|
| 301 | export.SaveMission( cur_mission, cur_mis) |
|---|
| 302 | print "DONE" |
|---|
| 303 | #----------------------------------------------------------------------- |
|---|
| 304 | if __name__ == "__main__": |
|---|
| 305 | pathname = os.path.abspath(os.path.dirname( sys.argv[0] )) |
|---|
| 306 | app = QApplication(sys.argv) |
|---|
| 307 | |
|---|
| 308 | #- Load traduction |
|---|
| 309 | locale = QLocale.system().name(); |
|---|
| 310 | |
|---|
| 311 | #-Debug |
|---|
| 312 | #locale = "fr_FR" |
|---|
| 313 | #locale = "en_US" |
|---|
| 314 | |
|---|
| 315 | translator = QTranslator() |
|---|
| 316 | translator.load(QString("lome_"+locale), QString(os.path.join(pathname, "i18n"))) |
|---|
| 317 | app.installTranslator(translator); |
|---|
| 318 | |
|---|
| 319 | cst_init( app ) |
|---|
| 320 | |
|---|
| 321 | try: |
|---|
| 322 | g_object = MergeTool(pathname) |
|---|
| 323 | g_object.show() |
|---|
| 324 | sys.exit(app.exec_()) |
|---|
| 325 | except SystemExit: |
|---|
| 326 | pass |
|---|
| 327 | except: |
|---|
| 328 | exceptionType, exceptionValue, exceptionTraceback = sys.exc_info() |
|---|
| 329 | msg_a = traceback.format_exception(exceptionType, exceptionValue, exceptionTraceback) |
|---|
| 330 | msg = "" |
|---|
| 331 | for m in msg_a: |
|---|
| 332 | msg += m |
|---|
| 333 | logging.getLogger('[ERROR]').debug(msg) |
|---|