OSDN Git Service

30c1c680d65a93626fbd59146c7a9853c19f57be
[gefu/Gefu.git] / simpletextview.cpp
1 #include "common.h"
2 #include "simpletextview.h"
3 #include "mainwindow.h"
4
5 #include <QDebug>
6 #include <QMenu>
7 #include <QSettings>
8 #include <QShortcut>
9 #include <QTextCodec>
10 #include <QStatusBar>
11
12 QString KeyEventToSequence(const QKeyEvent *event)
13 {
14     QString modifier = QString::null;
15     if (event->modifiers() & Qt::ShiftModifier)     { modifier += "Shift+"; }
16     if (event->modifiers() & Qt::ControlModifier)   { modifier += "Ctrl+"; }
17     if (event->modifiers() & Qt::AltModifier)       { modifier += "Alt+"; }
18     if (event->modifiers() & Qt::MetaModifier)      { modifier += "Meta+"; }
19
20     QString key = QKeySequence(event->key()).toString();
21     return QKeySequence(modifier + key).toString();
22 }
23
24 SimpleTextView::SimpleTextView(QWidget *parent) :
25     QPlainTextEdit(parent),
26     m_convEUC(NULL),
27     m_convJIS(NULL),
28     m_convSJIS(NULL),
29     m_convUTF8(NULL),
30     m_convUTF16BE(NULL),
31     m_convUTF16LE(NULL),
32     m_copy(NULL),
33     m_back(NULL)
34 {
35     setReadOnly(true);
36     updateAppearance();
37
38     setContextMenuPolicy(Qt::DefaultContextMenu);
39     m_convEUC = new QAction(tr("EUC-JPで再読込"), this);
40     m_convJIS = new QAction(tr("ISO 2022-JP(JIS)で再読込"), this);
41     m_convSJIS = new QAction(tr("Shift-JISで再読込"), this);
42     m_convUTF8 = new QAction(tr("UTF-8で再読込"), this);
43     m_convUTF16 = new QAction(tr("UTF-16で再読込"), this);
44     m_convUTF16BE = new QAction(tr("UTF-16BEで再読込"), this);
45     m_convUTF16LE = new QAction(tr("UTF-16LEで再読込"), this);
46     m_copy = new QAction(tr("選択範囲をクリップボードにコピー"), this);
47     m_back = new QAction(tr("戻る"), this);
48
49     m_convEUC->setObjectName("convertFromEUC");
50     m_convJIS->setObjectName("convertFromJIS");
51     m_convSJIS->setObjectName("convertFromSJIS");
52     m_convUTF8->setObjectName("convertFromUTF8");
53     m_convUTF16->setObjectName("convertFromUTF16");
54     m_convUTF16BE->setObjectName("convertFromUTF16BE");
55     m_convUTF16LE->setObjectName("convertFromUTF16LE");
56     m_copy->setObjectName("copy");
57     m_back->setObjectName("back");
58
59     m_convEUC->setShortcut(QKeySequence("Shift+E"));
60     m_convJIS->setShortcut(QKeySequence("Shift+J"));
61     m_convSJIS->setShortcut(QKeySequence("Shift+S"));
62     m_convUTF8->setShortcut(QKeySequence("Shift+U"));
63     m_convUTF16->setShortcut(QKeySequence("Shift+I"));
64     m_convUTF16BE->setShortcut(QKeySequence("Shift+O"));
65     m_convUTF16LE->setShortcut(QKeySequence("Shift+P"));
66     m_copy->setShortcut(QKeySequence::Copy);
67     m_back->setShortcut(QKeySequence("Return"));
68
69     QList<QKeySequence> shortcuts;
70     shortcuts = m_back->shortcuts();
71     shortcuts.append(QKeySequence("Backspace"));
72     m_back->setShortcuts(shortcuts);
73
74     connect(m_convEUC, SIGNAL(triggered()), this, SLOT(convertFromEUC()));
75     connect(m_convJIS, SIGNAL(triggered()), this, SLOT(convertFromJIS()));
76     connect(m_convSJIS, SIGNAL(triggered()), this, SLOT(convertFromSJIS()));
77     connect(m_convUTF8, SIGNAL(triggered()), this, SLOT(convertFromUTF8()));
78     connect(m_convUTF16, SIGNAL(triggered()), this, SLOT(convertFromUTF16()));
79     connect(m_convUTF16BE, SIGNAL(triggered()), this, SLOT(convertFromUTF16BE()));
80     connect(m_convUTF16LE, SIGNAL(triggered()), this, SLOT(convertFromUTF16LE()));
81     connect(m_copy, SIGNAL(triggered()), this, SLOT(copy()));
82     connect(m_back, SIGNAL(triggered()), this, SLOT(back()));
83
84     connect(this, SIGNAL(copyAvailable(bool)), this, SLOT(onCopyAvailable(bool)));
85
86     m_copy->setEnabled(false);
87 }
88
89 void SimpleTextView::setSource(const QByteArray &source)
90 {
91     m_source = source;
92
93     // BOMで文字コードを判別する
94     const char UTF8_BOM[] = { 0xEF, 0xBB, 0xBF };
95     const char UTF16BE_BOM[] = { 0xFE, 0xFF };
96     const char UTF16LE_BOM[] = { 0xFF, 0xFE };
97
98     if (m_source.indexOf(QByteArray(UTF8_BOM)) == 0) {
99         qDebug() << "Detect UTF-8 BOM";
100         convertFromUTF8();
101     }
102     else if (m_source.indexOf(QByteArray(UTF16BE_BOM)) == 0 ||
103              m_source.indexOf(QByteArray(UTF16LE_BOM)) == 0)
104     {
105         qDebug() << "Detect UTF-16 BOM";
106         convertFromUTF16();
107     }
108
109     QByteArray first1KB = m_source.left(1024);
110     // 文字コードを示す文字列で判別する
111     QTextCodec *codec = QTextCodec::codecForName("UTF-8");
112     QString text = codec->toUnicode(first1KB).toLower();
113     if (text.indexOf("utf8") != -1 || text.indexOf("utf-8") != -1) {
114         convertFromUTF8();
115         return;
116     }
117     if (text.indexOf("sjis") != -1 || text.indexOf("shift-jis") != -1 ||
118         text.indexOf("shift_jis") != -1)
119     {
120         convertFromSJIS();
121         return;
122     }
123     if (text.indexOf("euc") != -1 || text.indexOf("euc-jp") != -1 ||
124         text.indexOf("euc_jp") != -1)
125     {
126         convertFromEUC();
127         return;
128     }
129     if (text.indexOf("jis") != -1 || text.indexOf("iso 2022-jp") != -1) {
130         convertFromJIS();
131         return;
132     }
133
134     std::string code = detectCode(first1KB);
135     codec = QTextCodec::codecForName(code.c_str());
136     setPlainText(codec->toUnicode(m_source));
137     getMainWnd()->statusBar()->showMessage(code.c_str());
138 }
139
140 void SimpleTextView::updateAppearance()
141 {
142     QSettings settings;
143
144     QPalette pal = this->palette();
145     if (settings.value(IniKey_ViewerInherit).toBool()) {
146         pal.setColor(QPalette::Base,
147                      settings.value(IniKey_ViewColorBgNormal).value<QColor>());
148         pal.setColor(QPalette::Text,
149                      settings.value(IniKey_ViewColorFgNormal).value<QColor>());
150     }
151     else {
152         pal.setColor(QPalette::Base,
153                      settings.value(IniKey_ViewerColorBg).value<QColor>());
154         pal.setColor(QPalette::Text,
155                      settings.value(IniKey_ViewerColorFg).value<QColor>());
156     }
157     setPalette(pal);
158     setFont(settings.value(IniKey_ViewerFont).value<QFont>());
159 }
160
161 void SimpleTextView::convertFromEUC()
162 {
163     QTextCodec *codec = QTextCodec::codecForName("EUC-JP");
164     setPlainText(codec->toUnicode(m_source));
165     getMainWnd()->statusBar()->showMessage("EUC-JP");
166 }
167
168 void SimpleTextView::convertFromJIS()
169 {
170     QTextCodec *codec = QTextCodec::codecForName("ISO 2022-JP");
171     setPlainText(codec->toUnicode(m_source));
172     getMainWnd()->statusBar()->showMessage("ISO 2022-JP");
173 }
174
175 void SimpleTextView::convertFromSJIS()
176 {
177     QTextCodec *codec = QTextCodec::codecForName("Shift-JIS");
178     setPlainText(codec->toUnicode(m_source));
179     getMainWnd()->statusBar()->showMessage("Shift-JIS");
180
181 }
182
183 void SimpleTextView::convertFromUTF8()
184 {
185     QTextCodec *codec = QTextCodec::codecForName("UTF-8");
186     setPlainText(codec->toUnicode(m_source));
187     getMainWnd()->statusBar()->showMessage("UTF-8");
188 }
189
190 void SimpleTextView::convertFromUTF16()
191 {
192     QTextCodec *codec = QTextCodec::codecForName("UTF-16");
193     setPlainText(codec->toUnicode(m_source));
194     getMainWnd()->statusBar()->showMessage("UTF-16");
195 }
196
197 void SimpleTextView::convertFromUTF16BE()
198 {
199     QTextCodec *codec = QTextCodec::codecForName("UTF-16BE");
200     setPlainText(codec->toUnicode(m_source));
201     getMainWnd()->statusBar()->showMessage("UTF-16BE");
202 }
203
204 void SimpleTextView::convertFromUTF16LE()
205 {
206     QTextCodec *codec = QTextCodec::codecForName("UTF-16LE");
207     setPlainText(codec->toUnicode(m_source));
208     getMainWnd()->statusBar()->showMessage("UTF-16LE");
209 }
210
211 void SimpleTextView::onCopyAvailable(bool yes)
212 {
213     m_copy->setEnabled(yes);
214 }
215
216 void SimpleTextView::back()
217 {
218     emit viewFinished(this);
219 }
220
221 void SimpleTextView::keyPressEvent(QKeyEvent *event)
222 {
223     QString ksq = KeyEventToSequence(event);
224
225     if (ProcessShortcut(ksq, this)) {
226         event->accept();
227         return;
228     }
229
230     if (ProcessShortcut(ksq, getMainWnd())) {
231         event->accept();
232         return;
233     }
234
235     QPlainTextEdit::keyPressEvent(event);
236 }
237
238
239 void SimpleTextView::contextMenuEvent(QContextMenuEvent *event)
240 {
241     qDebug() << "contextMenuEvent();";
242     QMenu menu(this);
243     menu.addAction(m_convEUC);
244     menu.addAction(m_convJIS);
245     menu.addAction(m_convSJIS);
246     menu.addAction(m_convUTF8);
247     menu.addAction(m_convUTF16BE);
248     menu.addAction(m_convUTF16LE);
249     menu.addSeparator();
250     menu.addAction(m_copy);
251     menu.addSeparator();
252     menu.addAction(m_back);
253     menu.exec(event->globalPos());
254 }
255
256 // http://dobon.net/vb/dotnet/string/detectcode.html より拝借
257 std::string SimpleTextView::detectCode(const QByteArray &bytes)
258 {
259     typedef unsigned char byte;
260     const byte bEscape = 0x1B;
261     const byte bAt = 0x40;
262     const byte bDollar = 0x24;
263     const byte bAnd = 0x26;
264     const byte bOpen = 0x28;    //'('
265     const byte bB = 0x42;
266     const byte bD = 0x44;
267     const byte bJ = 0x4A;
268     const byte bI = 0x49;
269
270     int len = bytes.size();
271     byte b1, b2, b3, b4;
272
273     bool isBinary = false;
274     for (int i = 0; i < len; i++) {
275         b1 = bytes[i];
276         if (b1 <= 0x06 || b1 == 0x7F || b1 == 0xFF) {
277             //'binary'
278             isBinary = true;
279             if (b1 == 0x00 && i < len - 1 && static_cast<byte>(bytes[i + 1]) <= 0x7F) {
280                 return "UTF-16LE";
281             }
282         }
283     }
284     if (isBinary) {
285         return "UTF-8";
286     }
287
288     bool notJapanese = true;
289     for (int i = 0; i < len; i++) {
290         b1 = bytes[i];
291         if (b1 == bEscape || 0x80 <= b1) {
292             notJapanese = false;
293             break;
294         }
295     }
296     if (notJapanese) {
297         return "UTF-8";
298     }
299
300     for (int i = 0; i < len - 2; i++) {
301         b1 = bytes[i];
302         b2 = bytes[i + 1];
303         b3 = bytes[i + 2];
304
305         if (b1 == bEscape){
306             if ((b2 == bDollar && b3 == bAt) ||
307                 (b2 == bDollar && b3 == bB) ||
308                 (b2 == bOpen && (b3 == bB || b3 == bJ)) ||
309                 (b2 == bOpen && b3 == bI))
310             {
311                 return "ISO 2022-JP";
312             }
313             if (i < len - 3) {
314                 b4 = bytes[i + 3];
315                 if (b2 == bDollar && b3 == bOpen && b4 == bD) {
316                     return "ISO 2022-JP";
317                 }
318                 if (i < len - 5 &&
319                     b2 == bAnd && b3 == bAt && b4 == bEscape &&
320                     bytes[i + 4] == bDollar && bytes[i + 5] == bB)
321                 {
322                     return "ISO 2022-JP";
323                 }
324             }
325         }
326     }
327
328     int sjis = 0;
329     int euc = 0;
330     int utf8 = 0;
331     for (int i = 0; i < len - 1; i++) {
332         b1 = bytes[i];
333         b2 = bytes[i + 1];
334         if (((0x81 <= b1 && b1 <= 0x9F) || (0xE0 <= b1 && b1 <= 0xFC)) &&
335             ((0x40 <= b2 && b2 <= 0x7E) || (0x80 <= b2 && b2 <= 0xFC)))
336         {
337             sjis += 2;
338             i++;
339         }
340     }
341     for (int i = 0; i < len - 1; i++) {
342         b1 = bytes[i];
343         b2 = bytes[i + 1];
344         if (((0xA1 <= b1 && b1 <= 0xFE) && (0xA1 <= b2 && b2 <= 0xFE)) ||
345             (b1 == 0x8E && (0xA1 <= b2 && b2 <= 0xDF)))
346         {
347             euc += 2;
348             i++;
349         }
350         else if (i < len - 2) {
351             b3 = bytes[i + 2];
352             if (b1 == 0x8F && (0xA1 <= b2 && b2 <= 0xFE) &&
353                 (0xA1 <= b3 && b3 <= 0xFE))
354             {
355                 euc += 3;
356                 i += 2;
357             }
358         }
359     }
360     for (int i = 0; i < len - 1; i++) {
361         b1 = bytes[i];
362         b2 = bytes[i + 1];
363         if ((0xC0 <= b1 && b1 <= 0xDF) && (0x80 <= b2 && b2 <= 0xBF)) {
364             utf8 += 2;
365             i++;
366         }
367         else if (i < len - 2) {
368             b3 = bytes[i + 2];
369             if ((0xE0 <= b1 && b1 <= 0xEF) && (0x80 <= b2 && b2 <= 0xBF) &&
370                 (0x80 <= b3 && b3 <= 0xBF))
371             {
372                 utf8 += 3;
373                 i += 2;
374             }
375         }
376     }
377
378     if (euc > sjis && euc > utf8) {
379         return "EUC-JP";
380     }
381     else if (sjis > euc && sjis > utf8) {
382         return "Shift-JIS";
383     }
384     else if (utf8 > euc && utf8 > sjis) {
385         return "UTF-8";
386     }
387
388 #ifdef Q_OS_WIN
389     return "Shift-JIS";
390 #else
391     return "UTF-8";
392 #endif
393 }