~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to tools/linguist/linguist/msgedit.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the linguist application of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
/*  TRANSLATOR MsgEdit
 
30
 
 
31
  This is the right panel of the main window.
 
32
*/
 
33
 
 
34
#include "msgedit.h"
 
35
 
 
36
#include "trwindow.h"
 
37
#include "simtexth.h"
 
38
#include "messagemodel.h"
 
39
#include "phrasemodel.h"
 
40
 
 
41
#include <qmenu.h>
 
42
#include <qaction.h>
 
43
#include <qapplication.h>
 
44
#include <qclipboard.h>
 
45
#include <qlabel.h>
 
46
#include <qlayout.h>
 
47
#include <qtextedit.h>
 
48
#include <qpalette.h>
 
49
#include <qstring.h>
 
50
#include <qpainter.h>
 
51
#include <qscrollbar.h>
 
52
#include <qheaderview.h>
 
53
#include <qshortcut.h>
 
54
#include <qregexp.h>
 
55
#include <qdockwidget.h>
 
56
#include <qfont.h>
 
57
#include <qtreeview.h>
 
58
#include <qscrollarea.h>
 
59
#include <qtextdocumentfragment.h>
 
60
#include <qtextcursor.h>
 
61
#include <QTextBlock>
 
62
#include <QAbstractTextDocumentLayout>
 
63
 
 
64
static const int MaxCandidates = 5;
 
65
 
 
66
const char MessageEditor::backTab[] = "\a\b\f\n\r\t";
 
67
const char * const MessageEditor::friendlyBackTab[] = {
 
68
        QT_TRANSLATE_NOOP("MessageEditor", "bell"),
 
69
        QT_TRANSLATE_NOOP("MessageEditor", "backspace"),
 
70
        QT_TRANSLATE_NOOP("MessageEditor", "new page"),
 
71
        QT_TRANSLATE_NOOP("MessageEditor", "new line"),
 
72
        QT_TRANSLATE_NOOP("MessageEditor", "carriage return"),
 
73
        QT_TRANSLATE_NOOP("MessageEditor", "tab")
 
74
    };
 
75
 
 
76
void MessageEditor::visualizeBackTabs(const QString &text, QTextEdit *te)
 
77
{
 
78
    te->clear();
 
79
    QTextCursor tc(te->textCursor());
 
80
    QTextCharFormat blueFormat = defFormat;
 
81
    blueFormat.setForeground(QBrush(Qt::blue));
 
82
    blueFormat.setFontItalic(true);
 
83
    blueFormat.setProperty(QTextFormat::UserProperty, -1);
 
84
 
 
85
    QString plainText;
 
86
    for (int i = 0; i < (int) text.length(); ++i)
 
87
    {
 
88
        int ch = text[i].unicode();
 
89
        if (ch < 0x20)
 
90
        {
 
91
            if (!plainText.isEmpty())
 
92
            {
 
93
                tc.insertText(plainText, defFormat);
 
94
                plainText.clear();
 
95
            }
 
96
            const char *p = strchr(backTab, ch);
 
97
            // store the character in the user format property
 
98
            // in the first '(' in the phrase
 
99
            blueFormat.setProperty(QTextFormat::UserProperty, ch);
 
100
            tc.insertText(QString("("), blueFormat);
 
101
            blueFormat.setProperty(QTextFormat::UserProperty, -1);
 
102
            if (p == 0)
 
103
            {
 
104
                tc.insertText(QString::number(ch, 16) + ")", blueFormat);
 
105
            }
 
106
            else
 
107
            {
 
108
                tc.insertText(MessageEditor::tr(friendlyBackTab[p - backTab]) + ")",
 
109
                    blueFormat);
 
110
                if (backTab[p - backTab] == '\n')
 
111
                    tc.insertBlock();
 
112
            }
 
113
        }
 
114
        // if a space is by itself, at the end, or beside other spaces
 
115
        else if (ch == ' ')
 
116
        {
 
117
            if (i == 0 || i == text.length() - 1 || text[i - 1].isSpace() ||
 
118
                text[i + 1].isSpace())
 
119
            {
 
120
                blueFormat.setProperty(QTextFormat::UserProperty, ch);
 
121
                tc.insertText(QString("("), blueFormat);
 
122
                blueFormat.setProperty(QTextFormat::UserProperty, -1);
 
123
                tc.insertText(MessageEditor::tr("sp)"), blueFormat);
 
124
            }
 
125
            else
 
126
            {
 
127
                plainText += ' ';
 
128
            }
 
129
        }
 
130
        else
 
131
        {
 
132
            plainText += QString(ch);
 
133
        }
 
134
    }
 
135
    tc.insertText(plainText, defFormat);
 
136
}
 
137
 
 
138
SourceTextEdit::SourceTextEdit(QWidget *parent) : QTextEdit(parent)
 
139
{
 
140
    srcmenu = 0;
 
141
    actCopy = new QAction(tr("&Copy"), this);
 
142
    actCopy->setShortcut(QKeySequence(tr("Ctrl+C")));
 
143
    actSelect = new QAction(tr("Select &All"), this);
 
144
    actSelect->setShortcut(QKeySequence(tr("Ctrl+A")));
 
145
    connect(actCopy, SIGNAL(triggered()), this, SLOT(copySelection()));
 
146
    connect(actSelect, SIGNAL(triggered()), this, SLOT(selectAll()));
 
147
}
 
148
 
 
149
void SourceTextEdit::copySelection()
 
150
{
 
151
    QTextDocumentFragment tdf = textCursor().selection();
 
152
    QTextDocument td;
 
153
    QTextCursor tc(&td);
 
154
    tc.insertFragment(tdf);
 
155
    int ch;
 
156
 
 
157
    tc.movePosition(QTextCursor::Start);
 
158
    while(!tc.atEnd())
 
159
    {
 
160
        tc.movePosition(QTextCursor::NextCharacter);
 
161
        ch = tc.charFormat().intProperty(QTextFormat::UserProperty);
 
162
        if (ch != 0) // if wrong format
 
163
        {
 
164
            // delete char
 
165
            tc.deletePreviousChar();
 
166
            if (ch != -1) // insert backtab
 
167
                tc.insertText(QString(ch));
 
168
        }
 
169
    }
 
170
 
 
171
    QApplication::clipboard()->setText(td.toPlainText());
 
172
}
 
173
 
 
174
void SourceTextEdit::contextMenuEvent(QContextMenuEvent *e)
 
175
{
 
176
    if (!srcmenu)
 
177
    {
 
178
        srcmenu = new QMenu(this);
 
179
        srcmenu->addAction(actCopy);
 
180
        srcmenu->addAction(actSelect);
 
181
    }
 
182
 
 
183
    actCopy->setEnabled(textCursor().hasSelection());
 
184
    actSelect->setEnabled(!document()->isEmpty());
 
185
 
 
186
    srcmenu->popup(e->globalPos());
 
187
}
 
188
 
 
189
/*
 
190
   ShadowWidget class impl.
 
191
 
 
192
   Used to create a shadow like effect for a widget
 
193
*/
 
194
ShadowWidget::ShadowWidget(QWidget *parent)
 
195
    : QWidget(parent), sWidth(10), wMargin(3), childWgt(0)
 
196
{
 
197
 
 
198
}
 
199
 
 
200
ShadowWidget::ShadowWidget(QWidget *child, QWidget *parent)
 
201
    : QWidget(parent), sWidth(10), wMargin(3), childWgt(0)
 
202
{
 
203
    setWidget(child);
 
204
}
 
205
 
 
206
void ShadowWidget::setWidget(QWidget *child)
 
207
{
 
208
    childWgt = child;
 
209
    if (childWgt && childWgt->parent() != this) {
 
210
        childWgt->setParent(this);
 
211
        childWgt->move(0,0);
 
212
        childWgt->show();
 
213
    }
 
214
}
 
215
 
 
216
void ShadowWidget::resizeEvent(QResizeEvent *)
 
217
{
 
218
    if(childWgt) {
 
219
        childWgt->move(wMargin, wMargin);
 
220
        childWgt->resize(width() - sWidth - wMargin, height() - sWidth -
 
221
            wMargin);
 
222
    }
 
223
}
 
224
 
 
225
void ShadowWidget::paintEvent(QPaintEvent *e)
 
226
{
 
227
    QPainter p;
 
228
    int w = width() - sWidth;
 
229
    int h = height() - sWidth;
 
230
 
 
231
 
 
232
    if (!((w > 0) && (h > 0)))
 
233
        return;
 
234
 
 
235
    if (p.begin(this)) {
 
236
        p.setPen(palette().color(QPalette::Shadow));
 
237
 
 
238
        p.drawPoint(w + 5, 6);
 
239
        p.drawLine(w + 3, 6, w + 5, 8);
 
240
        p.drawLine(w + 1, 6, w + 5, 10);
 
241
        int i;
 
242
        for (i=7; i < h; i += 2)
 
243
            p.drawLine( w, i, w + 5, i + 5);
 
244
        for (i = w - i + h; i > 6; i -= 2)
 
245
            p.drawLine( i, h, i + 5, h + 5);
 
246
        for (; i > 0 ; i -= 2)
 
247
            p.drawLine( 6, h + 6 - i, i + 5, h + 5);
 
248
 
 
249
        p.end();
 
250
    }
 
251
    QWidget::paintEvent(e);
 
252
}
 
253
 
 
254
/*
 
255
   EditorPage class impl.
 
256
 
 
257
   A frame that contains the source text, translated text and any
 
258
   source code comments and hints.
 
259
*/
 
260
EditorPage::EditorPage(MessageEditor *parent, const char *name)
 
261
    : QFrame(parent)
 
262
{
 
263
    setObjectName(name);
 
264
    setLineWidth(1);
 
265
    setFrameStyle(QFrame::Box | QFrame::Plain);
 
266
 
 
267
    // Use white explicitly as the background color for the editor page.
 
268
    QPalette p = palette();
 
269
    p.setColor(QPalette::Active, QPalette::Base, QColor(Qt::white));
 
270
    p.setColor(QPalette::Inactive, QPalette::Base, QColor(Qt::white));
 
271
    p.setColor(QPalette::Disabled, QPalette::Base, QColor(Qt::white));
 
272
    p.setColor(QPalette::Active, QPalette::Background,
 
273
                p.color(QPalette::Active, QPalette::Base));
 
274
    p.setColor(QPalette::Inactive, QPalette::Background,
 
275
                p.color(QPalette::Inactive, QPalette::Base));
 
276
    p.setColor(QPalette::Disabled, QPalette::Background,
 
277
                p.color(QPalette::Disabled, QPalette::Base));
 
278
 
 
279
    parent->setPalette(p);
 
280
 
 
281
    srcTextLbl = new QLabel(tr("Source text"), this);
 
282
    transLbl   = new QLabel(tr("Translation"), this);
 
283
 
 
284
    QFont fnt = font();
 
285
    fnt.setBold(true);
 
286
    srcTextLbl->setFont(fnt);
 
287
    transLbl->setFont(fnt);
 
288
 
 
289
    srcText = new SourceTextEdit(this);
 
290
    srcText->setFrameStyle(QFrame::NoFrame);
 
291
    srcText->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding,
 
292
        QSizePolicy::Minimum));
 
293
    srcText->setAutoFormatting(QTextEdit::AutoNone);
 
294
    srcText->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
295
    srcText->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
296
    p = srcText->palette();
 
297
    p.setColor(QPalette::Disabled, QPalette::Base, p.color(QPalette::Active, QPalette::Base));
 
298
    srcText->setPalette( p );
 
299
        srcText->setReadOnly(true);
 
300
    connect(srcText->document(), SIGNAL(contentsChanged()), SLOT(handleSourceChanges()));
 
301
 
 
302
    cmtText = new QTextEdit(this);
 
303
    cmtText->setObjectName("comment/context view");
 
304
    cmtText->setFrameStyle( QFrame::NoFrame );
 
305
    cmtText->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding,
 
306
                                         QSizePolicy::Minimum ) );
 
307
    cmtText->setAutoFormatting(QTextEdit::AutoNone);
 
308
    cmtText->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
309
    cmtText->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
310
    p = cmtText->palette();
 
311
    p.setColor(QPalette::Active, QPalette::Base, QColor(236,245,255));
 
312
    p.setColor(QPalette::Inactive, QPalette::Base, QColor(236,245,255));
 
313
    cmtText->setPalette(p);
 
314
        cmtText->setReadOnly(true);
 
315
    connect(cmtText->document(), SIGNAL(contentsChanged()), SLOT(handleCommentChanges()));
 
316
 
 
317
    transText = new QTextEdit(this);
 
318
    transText->setObjectName("translation editor");
 
319
    transText->setFrameStyle(QFrame::NoFrame);
 
320
    transText->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding,
 
321
                                             QSizePolicy::MinimumExpanding));
 
322
    transText->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
323
    transText->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
324
    transText->setAutoFormatting(QTextEdit::AutoNone);
 
325
    transText->setLineWrapMode(QTextEdit::WidgetWidth);
 
326
    p = transText->palette();
 
327
    p.setColor(QPalette::Disabled, QPalette::Base, p.color(QPalette::Active, QPalette::Base));
 
328
    transText->setPalette(p);
 
329
    connect(transText->document(), SIGNAL(contentsChanged()),
 
330
             SLOT(handleTranslationChanges()));
 
331
 
 
332
    pageCurl = new PageCurl(this);
 
333
 
 
334
    // Focus
 
335
    setFocusPolicy(Qt::StrongFocus);
 
336
    parent->setFocusProxy(transText);
 
337
    transLbl->setFocusProxy(transText);
 
338
    srcTextLbl->setFocusProxy(transText);
 
339
    srcText->setFocusProxy(transText);
 
340
    cmtText->setFocusProxy(transText);
 
341
    setFocusProxy(transText);
 
342
 
 
343
    updateCommentField();
 
344
}
 
345
 
 
346
/*
 
347
   Don't show the comment field if there are no comments.
 
348
*/
 
349
void EditorPage::updateCommentField()
 
350
{
 
351
    if(cmtText->toPlainText().isEmpty())
 
352
        cmtText->hide();
 
353
    else
 
354
        cmtText->show();
 
355
 
 
356
    layoutWidgets();
 
357
}
 
358
 
 
359
/*
 
360
   Handle the widget layout manually
 
361
*/
 
362
void EditorPage::layoutWidgets()
 
363
 {
 
364
    int margin = 6;
 
365
    int space  = 2;
 
366
    int w = width();
 
367
 
 
368
    pageCurl->move(width() - pageCurl->width(), 0);
 
369
 
 
370
    QFontMetrics fm(srcTextLbl->font());
 
371
    srcTextLbl->move(margin, margin);
 
372
    srcTextLbl->resize(fm.width(srcTextLbl->text()), srcTextLbl->height());
 
373
 
 
374
    srcText->move(margin, srcTextLbl->y() + srcTextLbl->height() + space);
 
375
    srcText->resize(w - margin*2, srcText->height());
 
376
 
 
377
    cmtText->move(margin, srcText->y() + srcText->height() + space);
 
378
    cmtText->resize(w - margin*2, cmtText->height());
 
379
 
 
380
    if (cmtText->isHidden())
 
381
        transLbl->move(margin, srcText->y() + srcText->height() + space);
 
382
    else
 
383
        transLbl->move(margin, cmtText->y() + cmtText->height() + space);
 
384
    transLbl->resize( w - margin*2, transLbl->height() );
 
385
 
 
386
    transText->move(margin, transLbl->y() + transLbl->height() + space);
 
387
    transText->resize(w - margin*2, transText->height());
 
388
 
 
389
    // Calculate the total height for the editor page - emit a signal
 
390
    // if the actual page size is larger/smaller
 
391
    int totHeight = margin + srcTextLbl->height() +
 
392
                    srcText->height() + space +
 
393
                    transLbl->height() + space +
 
394
                    transText->height() + space +
 
395
                    frameWidth()*lineWidth()*2 + space * 3;
 
396
 
 
397
    if (!cmtText->isHidden())
 
398
        totHeight += cmtText->height() + space;
 
399
 
 
400
     if (height() != totHeight)
 
401
         emit pageHeightUpdated(totHeight);
 
402
}
 
403
 
 
404
void EditorPage::resizeEvent(QResizeEvent *)
 
405
{
 
406
    handleTranslationChanges();
 
407
    handleSourceChanges();
 
408
    handleCommentChanges();
 
409
    layoutWidgets();
 
410
}
 
411
 
 
412
void EditorPage::handleTranslationChanges()
 
413
{
 
414
    calculateFieldHeight(transText);
 
415
}
 
416
 
 
417
void EditorPage::handleSourceChanges()
 
418
{
 
419
    calculateFieldHeight(srcText);
 
420
}
 
421
 
 
422
void EditorPage::handleCommentChanges()
 
423
{
 
424
    calculateFieldHeight(cmtText);
 
425
}
 
426
 
 
427
/*
 
428
   Check if the translation text field is big enough to show all text
 
429
   that has been entered. If it isn't, resize it.
 
430
*/
 
431
void EditorPage::calculateFieldHeight(QTextEdit *field)
 
432
{
 
433
    int contentsHeight = qRound(field->document()->documentLayout()->documentSize().height());
 
434
 
 
435
    if (contentsHeight != field->height()) {
 
436
        int oldHeight = field->height();
 
437
        if(contentsHeight < 30)
 
438
            contentsHeight = 30;
 
439
        field->resize(field->width(), contentsHeight);
 
440
        emit pageHeightUpdated(height() + (field->height() - oldHeight));
 
441
    }
 
442
}
 
443
 
 
444
void EditorPage::fontChange(const QFont &)
 
445
{
 
446
    //keep the labels bold...
 
447
    QFont fnt = font();
 
448
 
 
449
    fnt.setBold(true);
 
450
    QFontMetrics fm(fnt);
 
451
    srcTextLbl->setFont(fnt);
 
452
    srcTextLbl->resize(fm.width(srcTextLbl->text()), srcTextLbl->height());
 
453
    transLbl->setFont(fnt);
 
454
    transLbl->resize(fm.width(transLbl->text()), transLbl->height());
 
455
    update();
 
456
}
 
457
 
 
458
/*
 
459
   MessageEditor class impl.
 
460
 
 
461
   Handle layout of dock windows and the editor page.
 
462
*/
 
463
MessageEditor::MessageEditor(MetaTranslator *t, QMainWindow *parent)
 
464
    : QScrollArea(parent), tor(t)
 
465
{
 
466
    doGuesses = true;
 
467
    canPaste = false;
 
468
    topDockWnd = new QDockWidget(parent);
 
469
    topDockWnd->setAllowedAreas(Qt::AllDockWidgetAreas);
 
470
    topDockWnd->setFeatures(QDockWidget::AllDockWidgetFeatures);
 
471
    topDockWnd->setWindowTitle(tr("Source text"));
 
472
 
 
473
    srcTextView = new QTreeView(topDockWnd);
 
474
    srcMdl = new MessageModel(topDockWnd);
 
475
    srcTextView->setModel(srcMdl);
 
476
    srcTextView->setAlternatingRowColors(true);
 
477
    srcTextView->setSelectionBehavior(QAbstractItemView::SelectRows);
 
478
    srcTextView->setSelectionMode(QAbstractItemView::SingleSelection);
 
479
    srcTextView->setRootIsDecorated(false);
 
480
    srcTextView->setUniformRowHeights(true);
 
481
    QPalette pal = srcTextView->palette();
 
482
    pal.setColor(QPalette::AlternateBase, TREEVIEW_ODD_COLOR);
 
483
    srcTextView->setPalette(pal);
 
484
 
 
485
    QFontMetrics fm(font());
 
486
    srcTextView->header()->setResizeMode(1, QHeaderView::Stretch);
 
487
    srcTextView->header()->resizeSection(0, fm.width(MessageModel::tr("Done")) + 20);
 
488
    srcTextView->header()->resizeSection(2, 300);
 
489
    srcTextView->header()->setClickable(true);
 
490
 
 
491
    topDockWnd->setWidget(srcTextView);
 
492
    parent->addDockWidget(Qt::TopDockWidgetArea, topDockWnd);
 
493
 
 
494
    bottomDockWnd = new QDockWidget(parent);
 
495
    bottomDockWnd->setAllowedAreas(Qt::AllDockWidgetAreas);
 
496
    bottomDockWnd->setFeatures(QDockWidget::AllDockWidgetFeatures);
 
497
    bottomDockWnd->setWindowTitle(tr("Phrases"));
 
498
 
 
499
    QWidget *w = new QWidget(bottomDockWnd);
 
500
    w->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
 
501
    QVBoxLayout *vl = new QVBoxLayout(w);
 
502
    vl->setSpacing(6);
 
503
 
 
504
    phraseLbl = new QLabel( tr("Phrases and guesses:"), w );
 
505
 
 
506
    phraseTv = new QTreeView(w);
 
507
    phraseTv->setObjectName("phrase list view");
 
508
    phrMdl = new PhraseModel(w);
 
509
    phraseTv->setModel(phrMdl);
 
510
    phraseTv->setAlternatingRowColors(true);
 
511
    phraseTv->setSelectionBehavior(QAbstractItemView::SelectRows);
 
512
    phraseTv->setSelectionMode(QAbstractItemView::SingleSelection);
 
513
    phraseTv->setRootIsDecorated(false);
 
514
    pal = phraseTv->palette();
 
515
    pal.setColor(QPalette::AlternateBase, TREEVIEW_ODD_COLOR);
 
516
    phraseTv->setPalette(pal);
 
517
 
 
518
    phraseTv->header()->setResizeMode(QHeaderView::Stretch);
 
519
    phraseTv->header()->setClickable(true);
 
520
 
 
521
    vl->addWidget(phraseLbl);
 
522
    vl->addWidget(phraseTv);
 
523
 
 
524
    for (int i = 0; i < 9; ++i) {
 
525
        (void) new GuessShortcut(i, this, SLOT(guessActivated(int)));
 
526
    }
 
527
 
 
528
    bottomDockWnd->setWidget(w);
 
529
    parent->addDockWidget(Qt::BottomDockWidgetArea, bottomDockWnd);
 
530
 
 
531
    setObjectName("scroll area");
 
532
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
533
    setFrameStyle(QFrame::NoFrame);
 
534
 
 
535
    editorPage = new EditorPage(this, "editor page");
 
536
    connect(editorPage, SIGNAL(pageHeightUpdated(int)),
 
537
             SLOT(updatePageHeight(int)));
 
538
 
 
539
    sw = new ShadowWidget(editorPage, this);
 
540
    sw->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
 
541
    sw->setMinimumSize(QSize(100, 150));
 
542
 
 
543
    setWidget(sw);
 
544
    defFormat = editorPage->srcText->currentCharFormat();
 
545
    editorPage->transText->installEventFilter(this);
 
546
 
 
547
    // Signals
 
548
    connect(editorPage->pageCurl, SIGNAL(nextPage()),
 
549
        SIGNAL(nextUnfinished()));
 
550
    connect(editorPage->pageCurl, SIGNAL(prevPage()),
 
551
        SIGNAL(prevUnfinished()));
 
552
 
 
553
    connect(editorPage->transText->document(), SIGNAL(contentsChanged()),
 
554
        this, SLOT(emitTranslationChanged()));
 
555
    connect(editorPage->transText->document(), SIGNAL(contentsChanged()),
 
556
        this, SLOT(updateButtons()));
 
557
    connect(editorPage->transText->document(), SIGNAL(undoAvailable(bool)),
 
558
        this, SIGNAL(undoAvailable(bool)));
 
559
    connect(editorPage->transText->document(), SIGNAL(redoAvailable(bool)),
 
560
        this, SIGNAL(redoAvailable(bool)));
 
561
    connect(editorPage->transText, SIGNAL(copyAvailable(bool)),
 
562
        this, SIGNAL(cutAvailable(bool)));
 
563
    connect(editorPage->transText, SIGNAL(copyAvailable(bool)),
 
564
        this, SIGNAL(copyAvailable(bool)));
 
565
    connect(qApp->clipboard(), SIGNAL(dataChanged()),
 
566
        this, SLOT(updateCanPaste()));
 
567
    connect(phraseTv, SIGNAL(doubleClicked(QModelIndex)),
 
568
        this, SLOT(insertPhraseInTranslation(QModelIndex)));
 
569
 
 
570
    phraseTv->installEventFilter(this);
 
571
 
 
572
    connect(srcTextView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
 
573
             parent, SLOT(showNewCurrent(QModelIndex,QModelIndex)));
 
574
 
 
575
    // What's this
 
576
    this->setWhatsThis(tr("This whole panel allows you to view and edit "
 
577
                              "the translation of some source text.") );
 
578
    editorPage->srcText->setWhatsThis(tr("This area shows the source text.") );
 
579
    editorPage->cmtText->setWhatsThis(tr("This area shows a comment that"
 
580
                        " may guide you, and the context in which the text"
 
581
                        " occurs.") );
 
582
    editorPage->transText->setWhatsThis(tr("This is where you can enter or modify"
 
583
                        " the translation of some source text.") );
 
584
 
 
585
    showNothing();
 
586
}
 
587
 
 
588
bool MessageEditor::eventFilter(QObject *o, QEvent *e)
 
589
{
 
590
    // handle copying from the source
 
591
    if ((e->type() == QEvent::KeyPress) ||
 
592
        (e->type() == QEvent::ShortcutOverride))
 
593
    {
 
594
        QKeyEvent *ke = static_cast<QKeyEvent *>(e);
 
595
 
 
596
        // handle return key in phrase list
 
597
        if (o == phraseTv
 
598
            && e->type() == QEvent::KeyPress
 
599
            && ke->modifiers() == Qt::NoModifier
 
600
            && ke->key() == Qt::Key_Return
 
601
            && phraseTv->currentIndex().isValid())
 
602
        {
 
603
            insertPhraseInTranslationAndLeave(phraseTv->currentIndex());
 
604
            return false;
 
605
        }
 
606
 
 
607
        if (ke->modifiers() & Qt::ControlModifier)
 
608
        {
 
609
            if ((ke->key() == Qt::Key_A) &&
 
610
                editorPage->srcText->underMouse())
 
611
            {
 
612
                editorPage->srcText->selectAll();
 
613
                return true;
 
614
            }
 
615
            if ((ke->key() == Qt::Key_C) &&
 
616
                editorPage->srcText->textCursor().hasSelection() &&
 
617
                editorPage->srcText->underMouse())
 
618
            {
 
619
                editorPage->srcText->copySelection();
 
620
                return true;
 
621
            }
 
622
        }
 
623
    }
 
624
 
 
625
    return QScrollArea::eventFilter(o, e);
 
626
}
 
627
 
 
628
void MessageEditor::updatePageHeight(int height)
 
629
{
 
630
    sw->resize(sw->width(), height + sw->margin() + sw->shadowWidth());
 
631
}
 
632
 
 
633
void MessageEditor::resizeEvent(QResizeEvent *e)
 
634
{
 
635
    sw->resize(viewport()->width(), sw->height());
 
636
    QScrollArea::resizeEvent(e);
 
637
}
 
638
 
 
639
QTreeView *MessageEditor::sourceTextView() const
 
640
{
 
641
    return srcTextView;
 
642
}
 
643
 
 
644
QTreeView *MessageEditor::phraseView() const
 
645
{
 
646
    return phraseTv;
 
647
}
 
648
 
 
649
void MessageEditor::showNothing()
 
650
{
 
651
    editorPage->srcText->clear();
 
652
 
 
653
    setEditionEnabled(false);
 
654
    sourceText.clear();
 
655
    editorPage->cmtText->clear();
 
656
    setTranslation(QString(), false);
 
657
    editorPage->handleSourceChanges();
 
658
    editorPage->handleCommentChanges();
 
659
    editorPage->handleTranslationChanges();
 
660
    editorPage->updateCommentField();
 
661
}
 
662
 
 
663
void MessageEditor::showMessage(const QString &text,
 
664
                                const QString &comment,
 
665
                                const QString &fullContext,
 
666
                                const QString &translation,
 
667
                                MetaTranslatorMessage::Type type,
 
668
                                const QList<Phrase> &phrases)
 
669
{
 
670
    phraseTv->clearSelection();
 
671
 
 
672
    bool obsolete = (type == MetaTranslatorMessage::Obsolete);
 
673
    setEditionEnabled(!obsolete);
 
674
    sourceText = text;
 
675
 
 
676
    visualizeBackTabs(text, editorPage->srcText);
 
677
 
 
678
    if (!fullContext.isEmpty() && !comment.isEmpty())
 
679
        visualizeBackTabs(fullContext.simplified() + "\n" +
 
680
            comment.simplified(), editorPage->cmtText);
 
681
    else if (!fullContext.isEmpty() && comment.isEmpty())
 
682
        visualizeBackTabs(fullContext.simplified(), editorPage->cmtText);
 
683
    else if (fullContext.isEmpty() && !comment.isEmpty())
 
684
        visualizeBackTabs(comment.simplified(), editorPage->cmtText);
 
685
    else
 
686
        editorPage->cmtText->clear();
 
687
 
 
688
    setTranslation(translation, false);
 
689
    phrMdl->removePhrases();
 
690
 
 
691
    foreach(Phrase p, phrases) {
 
692
        phrMdl->addPhrase(p);
 
693
    }
 
694
 
 
695
    if (doGuesses && !sourceText.isEmpty()) {
 
696
        CandidateList cl = similarTextHeuristicCandidates(tor,
 
697
            sourceText.toLatin1(), MaxCandidates);
 
698
        int n = 0;
 
699
        QList<Candidate>::Iterator it = cl.begin();
 
700
        while (it != cl.end()) {
 
701
            QString def;
 
702
            if (n < 9)
 
703
                def = tr("Guess (%1)").arg(QString(QKeySequence(Qt::CTRL | (Qt::Key_0 + (n + 1)))));
 
704
            else
 
705
                def = tr("Guess");
 
706
            phrMdl->addPhrase(Phrase((*it).source, (*it).target, def, n));
 
707
            ++n;
 
708
            ++it;
 
709
        }
 
710
    }
 
711
    phrMdl->resort();
 
712
    editorPage->handleSourceChanges();
 
713
    editorPage->handleCommentChanges();
 
714
    editorPage->handleTranslationChanges();
 
715
    editorPage->updateCommentField();
 
716
}
 
717
 
 
718
void MessageEditor::setTranslation(const QString &translation, bool emitt)
 
719
{
 
720
    // Block signals so that a signal is not emitted when
 
721
    // for example a new source text item is selected and *not*
 
722
    // the actual translation.
 
723
    if (!emitt)
 
724
        editorPage->transText->document()->blockSignals(true);
 
725
 
 
726
    if (translation.isNull())
 
727
        editorPage->transText->clear();
 
728
    else
 
729
        editorPage->transText->setPlainText(translation);
 
730
 
 
731
    if (!emitt)
 
732
    {
 
733
        editorPage->transText->document()->blockSignals(false);
 
734
 
 
735
        //don't undo the change
 
736
        emit undoAvailable(false);
 
737
        emit redoAvailable(false);
 
738
        updateButtons();
 
739
    }
 
740
    emit cutAvailable(false);
 
741
    emit copyAvailable(false);
 
742
}
 
743
 
 
744
void MessageEditor::setEditionEnabled(bool enabled)
 
745
{
 
746
    editorPage->transLbl->setEnabled(enabled);
 
747
    editorPage->transText->setReadOnly(!enabled);
 
748
 
 
749
    phraseLbl->setEnabled(enabled);
 
750
    phraseTv->setEnabled(enabled);
 
751
    updateCanPaste();
 
752
}
 
753
 
 
754
void MessageEditor::undo()
 
755
{
 
756
    editorPage->transText->document()->undo();
 
757
}
 
758
 
 
759
void MessageEditor::redo()
 
760
{
 
761
    editorPage->transText->document()->redo();
 
762
}
 
763
 
 
764
void MessageEditor::cut()
 
765
{
 
766
    editorPage->transText->cut();
 
767
}
 
768
 
 
769
void MessageEditor::copy()
 
770
{
 
771
    editorPage->transText->copy();
 
772
}
 
773
 
 
774
void MessageEditor::paste()
 
775
{
 
776
    editorPage->transText->paste();
 
777
}
 
778
 
 
779
void MessageEditor::selectAll()
 
780
{
 
781
    editorPage->transText->selectAll();
 
782
}
 
783
 
 
784
void MessageEditor::emitTranslationChanged()
 
785
{
 
786
    emit translationChanged(editorPage->transText->toPlainText());
 
787
}
 
788
 
 
789
void MessageEditor::guessActivated(int key)
 
790
{
 
791
    QModelIndex mi;
 
792
    Phrase p;
 
793
 
 
794
    for (int i=0; i<phrMdl->phraseList().count(); ++i) {
 
795
        mi = phrMdl->QAbstractTableModel::index(i, 0);
 
796
        p = phrMdl->phrase(mi);
 
797
        if (p.shortcut() == key) {
 
798
            insertPhraseInTranslation(mi);
 
799
            break;
 
800
        }
 
801
    }
 
802
}
 
803
 
 
804
void MessageEditor::insertPhraseInTranslation(const QModelIndex &index)
 
805
{
 
806
    if (!editorPage->transText->isReadOnly())
 
807
    {
 
808
        editorPage->transText->textCursor().insertText(phrMdl->phrase(index).target());
 
809
        emit translationChanged(editorPage->transText->toPlainText());
 
810
    }
 
811
}
 
812
 
 
813
void MessageEditor::insertPhraseInTranslationAndLeave(const QModelIndex &index)
 
814
{
 
815
    if (!editorPage->transText->isReadOnly())
 
816
    {
 
817
        editorPage->transText->textCursor().insertText(phrMdl->phrase(index).target());
 
818
        emit translationChanged(editorPage->transText->toPlainText());
 
819
        editorPage->transText->setFocus();
 
820
    }
 
821
}
 
822
 
 
823
void MessageEditor::updateButtons()
 
824
{
 
825
    bool overwrite = (!editorPage->transText->isReadOnly() &&
 
826
             (editorPage->transText->toPlainText().trimmed().isEmpty() ||
 
827
              mayOverwriteTranslation));
 
828
    mayOverwriteTranslation = false;
 
829
    emit updateActions(overwrite);
 
830
}
 
831
 
 
832
void MessageEditor::beginFromSource()
 
833
{
 
834
    mayOverwriteTranslation = true;
 
835
    setTranslation(sourceText, true);
 
836
    setEditorFocus();
 
837
}
 
838
 
 
839
void MessageEditor::setEditorFocus()
 
840
{
 
841
    if (!editorPage->hasFocus())
 
842
        editorPage->setFocus();
 
843
}
 
844
 
 
845
void MessageEditor::updateCanPaste()
 
846
{
 
847
    bool oldCanPaste = canPaste;
 
848
    canPaste = (!editorPage->transText->isReadOnly() &&
 
849
        !qApp->clipboard()->text().isNull());
 
850
    if (canPaste != oldCanPaste)
 
851
        emit pasteAvailable(canPaste);
 
852
}
 
853
 
 
854
void MessageEditor::toggleGuessing()
 
855
{
 
856
    doGuesses = !doGuesses;
 
857
    if (!doGuesses) {
 
858
        phrMdl->removePhrases();
 
859
    }
 
860
}