Linux multi-monitor fullscreen support
[ryzomcore.git] / studio / src / plugins / translation_manager / uxt_editor.cpp
blob06e6f98b46e5bad2d6e76a0cd5ed6526bb555b31
1 // Ryzom Core Studio - Translation Manager Plugin
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "translation_manager_constants.h"
19 #include "uxt_editor.h"
21 #include <QTableWidget>
22 #include <QFormLayout>
23 #include <QCloseEvent>
24 #include <QContextMenuEvent>
25 #include <QMessageBox>
26 #include <QMenu>
27 #include <QFileDialog>
29 #include <QFile>
30 #include <QTextStream>
32 #include "nel/misc/diff_tool.h"
33 #include "nel/misc/i18n.h"
35 namespace
38 QString getLang( const QString &fn )
40 QString lang = fn;
41 int idx = lang.lastIndexOf( '/' );
42 if( idx == -1 )
43 return "";
45 lang = lang.mid( idx + 1 );
46 idx = lang.lastIndexOf( '.' );
47 if( idx == -1 )
48 return "";
50 lang = lang.left( idx );
51 return lang;
56 namespace TranslationManager
59 void markItemTranslated( QTableWidgetItem *item )
61 item->setBackground( QColor::fromRgb( 126, 247, 134 ) );
64 void markItemUntranslated( QTableWidgetItem *item )
66 item->setBackground( QColor::fromRgb( 247, 126, 126 ) );
69 class UXTEditorPvt
71 public:
73 UXTEditorPvt()
75 t = new QTableWidget();
76 loadedFromWK = false;
79 QTableWidget *t;
80 std::vector< STRING_MANAGER::TStringInfo > infos;
81 bool loadedFromWK;
85 UXTEditor::UXTEditor( QMdiArea *parent ) :
86 CEditor( parent )
88 editor_type = Constants::ED_UXT;
89 setAttribute( Qt::WA_DeleteOnClose );
91 d_ptr = new UXTEditorPvt();
93 blockTableSignals( false );
96 UXTEditor::~UXTEditor()
98 delete d_ptr;
99 d_ptr = NULL;
102 void UXTEditor::open( QString filename )
104 std::vector< STRING_MANAGER::TStringInfo > &infos = d_ptr->infos;
105 QString lang = getLang( filename );
107 infos.clear();
108 STRING_MANAGER::loadStringFile( filename.toUtf8().constData(), infos, false );
110 if( d_ptr->infos.size() == 0 )
112 // The work file cannot be found, cannot proceed
113 if( filename.endsWith( "wk.uxt" ) )
115 QMessageBox::critical( this,
116 tr( "Error opening file.." ),
117 tr( "There was an error opening wk.uxt" ) );
118 return;
121 int l = filename.lastIndexOf( "/" );
122 if( l == -1 )
123 return;
125 QString fn = filename.left( l );
126 fn += "/wk.uxt";
128 // The work file cannot be found, cannot proceed
129 STRING_MANAGER::loadStringFile( fn.toUtf8().constData(), infos, true );
130 if( d_ptr->infos.size() == 0 )
132 QMessageBox::critical( this,
133 tr( "Error opening Uxt file" ),
134 tr( "Neither the specified file nor wk.uxt could be opened." ) );
135 return;
138 d_ptr->loadedFromWK = true;
141 blockTableSignals( true );
143 d_ptr->t->clear();
144 d_ptr->t->setColumnCount( 2 );
145 d_ptr->t->setRowCount( infos.size() );
147 setHeaderText( "Id", lang.toUpper() + " Text" );
149 int i = 0;
151 std::vector< STRING_MANAGER::TStringInfo >::const_iterator itr = infos.begin();
152 while( itr != infos.end() )
154 const STRING_MANAGER::TStringInfo &info = *itr;
156 QTableWidgetItem *name = new QTableWidgetItem( info.Identifier.c_str() );
157 QTableWidgetItem *text1 = new QTableWidgetItem( info.Text.toUtf8().c_str() );
159 d_ptr->t->setItem( i, 0, name );
160 d_ptr->t->setItem( i, 1, text1 );
162 if( ( info.HashValue != 0 ) && !d_ptr->loadedFromWK )
164 markItemTranslated( name );
165 markItemTranslated( text1 );
167 else
169 markItemUntranslated( name );
170 markItemUntranslated( text1 );
173 ++itr;
174 i++;
177 d_ptr->t->resizeColumnsToContents();
179 blockTableSignals( false );
181 setWidget( d_ptr->t );
183 current_file = filename;
184 setWindowTitle( filename + "[*]" );
185 setWindowFilePath( filename );
188 void UXTEditor::save()
190 saveAs( current_file );
193 void UXTEditor::saveAs( QString filename )
195 QFile f( filename );
196 if( !f.open( QIODevice::WriteOnly ) )
197 return;
199 QTextStream out( &f );
201 int idx = 0;
202 std::vector< STRING_MANAGER::TStringInfo >::const_iterator itr = d_ptr->infos.begin();
203 while( itr != d_ptr->infos.end() )
205 uint64 hash = 0;
207 // If text2 is not empty we can assume the string was translated, so we store with the correct hash
208 // If text2 is empty, it wasn't translated so we can just use the old hash.
209 // Additionally, if the strings were loaded from the wk.uxt file, we use a hash of 0 so we know it was not translated
210 if( itr->Text2.empty() )
212 if( d_ptr->loadedFromWK )
213 hash = 0;
214 else
215 hash = itr->HashValue;
217 else
219 hash = NLMISC::CI18N::makeHash( itr->Text2 );
222 QString hashLine = "// HASH_VALUE ";
223 hashLine += QString( NLMISC::CI18N::hashToString( hash ).c_str() ).toUpper();
224 hashLine += "\r\n";
226 QString idxLine = "// INDEX ";
227 idxLine += QString::number( idx );
228 idxLine += "\r\n";
231 QString trLine = "";
232 trLine += itr->Identifier.c_str();
233 trLine += "\t";
234 trLine += "[";
236 if( itr->Text2.empty() )
237 trLine += itr->Text.toUtf8().c_str();
238 else
239 trLine += itr->Text2.toUtf8().c_str();
241 trLine += "]";
242 trLine += "\r\n";
244 QString newLine = "\r\n";
246 out << hashLine;
247 out << idxLine;
248 out << trLine;
249 out << newLine;
251 ++itr;
252 idx++;
255 f.close();
257 setWindowModified( false );
260 void UXTEditor::activateWindow()
262 showMaximized();
266 void UXTEditor::insertRow()
268 blockTableSignals( true );
270 d_ptr->infos.push_back( STRING_MANAGER::TStringInfo() );
271 d_ptr->t->setRowCount( d_ptr->t->rowCount() + 1 );
272 int row = d_ptr->t->rowCount() - 1;
274 QTableWidgetItem *item1 = new QTableWidgetItem();
275 QTableWidgetItem *item2 = new QTableWidgetItem();
276 d_ptr->t->setItem( row, 0, item1 );
277 d_ptr->t->setItem( row, 1, item2 );
279 markRowUntranslated( row );
281 setWindowModified( true );
283 blockTableSignals( false );
287 void UXTEditor::deleteRow()
289 int r = d_ptr->t->currentRow();
290 if( r < 0 )
291 return;
293 int answer = QMessageBox::question( this,
294 tr( "Deleting a row" ),
295 tr( "Are you sure you want to delete this row?" ),
296 QMessageBox::Yes,
297 QMessageBox::Cancel );
298 if( QMessageBox::Yes != answer )
299 return;
301 std::vector< STRING_MANAGER::TStringInfo >::iterator itr = d_ptr->infos.begin();
302 itr += r;
303 d_ptr->infos.erase( itr );
305 d_ptr->t->removeRow( r );
307 setWindowModified( true );
310 void UXTEditor::closeEvent( QCloseEvent *e )
312 if( isWindowModified() )
314 int reply = QMessageBox::question( this,
315 tr( "Table changed" ),
316 tr( "The table has changed. Would you like to save your changes?" ),
317 QMessageBox::Yes,
318 QMessageBox::No
321 if( reply == QMessageBox::Yes )
322 save();
326 e->accept();
327 close();
330 void UXTEditor::contextMenuEvent( QContextMenuEvent *e )
332 QMenu *menu = new QMenu( this );
333 QAction *insertAction = new QAction( "Insert row", menu );
334 QAction *deleteAction = new QAction( "Delete row", menu );
335 QAction *markAction = new QAction( "Mark translated", menu );
336 QAction *unmarkAction = new QAction( "Mark not-translated", menu );
337 QAction *saveAction = new QAction( "Save", menu );
338 QAction *saveAsAction = new QAction( "Save as..", menu );
340 connect( insertAction, SIGNAL( triggered( bool ) ), this, SLOT( insertRow() ) );
341 connect( deleteAction, SIGNAL( triggered( bool ) ), this, SLOT( deleteRow() ) );
342 connect( markAction, SIGNAL( triggered( bool ) ), this, SLOT( markTranslated() ) );
343 connect( unmarkAction, SIGNAL( triggered( bool ) ), this, SLOT( markUntranslated() ) );
344 connect( saveAction, SIGNAL( triggered( bool ) ), this, SLOT( onSaveClicked() ) );
345 connect( saveAsAction, SIGNAL( triggered( bool ) ), this, SLOT( onSaveAsClicked() ) );
347 menu->addAction( insertAction );
348 menu->addAction( deleteAction );
349 menu->addAction( markAction );
350 menu->addAction( unmarkAction );
351 menu->addAction( saveAction );
352 menu->addAction( saveAsAction );
353 menu->exec( e->globalPos() );
356 void UXTEditor::onCellChanged( int row, int column )
358 QTableWidgetItem *item = d_ptr->t->item( row, column );
359 STRING_MANAGER::TStringInfo &info = d_ptr->infos[ row ];
361 if( column == 0 )
362 info.Identifier = item->text().toUtf8().constData();
363 else
364 if( column == 1 )
365 info.Text2 = item->text().toUtf8().constData();
367 setWindowModified( true );
369 markRowTranslated( row );
372 void UXTEditor::markTranslated()
374 int r = d_ptr->t->currentRow();
375 if( r < 0 )
376 return;
378 STRING_MANAGER::TStringInfo &info = d_ptr->infos[ r ];
379 if( !info.Text2.empty() )
380 return;
382 info.Text2 = info.Text;
384 setWindowModified( true );
386 markRowTranslated( r );
389 void UXTEditor::markUntranslated()
391 int r = d_ptr->t->currentRow();
392 if( r < 0 )
393 return;
395 STRING_MANAGER::TStringInfo &info = d_ptr->infos[ r ];
397 info.Text2.clear();
398 info.HashValue = 0;
400 setWindowModified( true );
402 markRowUntranslated( r );
405 void UXTEditor::onSaveClicked()
407 save();
410 void UXTEditor::onSaveAsClicked()
412 QString path = current_file;
413 int idx = path.lastIndexOf( '/' );
414 if( idx < 0 )
415 path = "";
416 else
417 path = path.left( idx + 1 );
419 QString file = QFileDialog::getSaveFileName( this,
420 tr( "Save Uxt as.." ),
421 path,
422 tr( "Uxt files ( *.uxt)" ) );
424 if( file.isEmpty() )
425 return;
427 saveAs( file );
430 void UXTEditor::setHeaderText( const QString &id, const QString &text )
432 QTableWidgetItem *h1 = new QTableWidgetItem( id );
433 QTableWidgetItem *h2 = new QTableWidgetItem( text );
434 h1->setTextAlignment( Qt::AlignLeft );
435 h2->setTextAlignment( Qt::AlignLeft );
436 d_ptr->t->setHorizontalHeaderItem( 0, h1 );
437 d_ptr->t->setHorizontalHeaderItem( 1, h2 );
440 void UXTEditor::blockTableSignals( bool block )
442 if( block )
443 disconnect( d_ptr->t, SIGNAL( cellChanged( int, int ) ), this, SLOT( onCellChanged( int, int ) ) );
444 else
445 connect( d_ptr->t, SIGNAL( cellChanged( int, int ) ), this, SLOT( onCellChanged( int, int ) ) );
448 void UXTEditor::markRowTranslated( int row )
450 blockTableSignals( true );
452 QTableWidgetItem *item1 = d_ptr->t->item( row, 0 );
453 QTableWidgetItem *item2 = d_ptr->t->item( row, 1 );
454 markItemTranslated( item1 );
455 markItemTranslated( item2 );
457 blockTableSignals( false );
460 void UXTEditor::markRowUntranslated( int row )
462 blockTableSignals( true );
464 QTableWidgetItem *item1 = d_ptr->t->item( row, 0 );
465 QTableWidgetItem *item2 = d_ptr->t->item( row, 1 );
466 markItemUntranslated( item1 );
467 markItemUntranslated( item2 );
469 blockTableSignals( false );