VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/softkeyboard/UISoftKeyboard.cpp

Last change on this file was 106061, checked in by vboxsync, 2 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 154.6 KB
Line 
1/* $Id: UISoftKeyboard.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISoftKeyboard class implementation.
4 */
5
6/*
7 * Copyright (C) 2016-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QApplication>
30#include <QCheckBox>
31#include <QColorDialog>
32#include <QComboBox>
33#include <QDir>
34#include <QFile>
35#include <QGroupBox>
36#include <QInputDialog>
37#include <QHeaderView>
38#include <QLabel>
39#include <QLineEdit>
40#include <QListWidget>
41#include <QPainter>
42#include <QPainterPath>
43#include <QPicture>
44#include <QPushButton>
45#include <QSplitter>
46#include <QStatusBar>
47#include <QStyle>
48#include <QStackedWidget>
49#include <QToolButton>
50#include <QXmlStreamReader>
51#include <QVBoxLayout>
52
53/* GUI includes: */
54#include "UICommon.h"
55#include "UIDesktopWidgetWatchdog.h"
56#include "UIExtraDataManager.h"
57#include "UIGlobalSession.h"
58#include "UIHelpBrowserDialog.h"
59#include "UIIconPool.h"
60#include "UILoggingDefs.h"
61#include "UIMachine.h"
62#include "UIMessageCenter.h"
63#include "UIModalWindowManager.h"
64#include "UISoftKeyboard.h"
65#include "UITranslationEventListener.h"
66#ifdef VBOX_WS_MAC
67# include "VBoxUtils-darwin.h"
68#endif
69
70/* External includes: */
71# include <math.h>
72
73/* Forward declarations: */
74class UISoftKeyboardColorButton;
75class UISoftKeyboardLayout;
76class UISoftKeyboardRow;
77class UISoftKeyboardWidget;
78
79const int iMessageTimeout = 3000;
80/** Key position are used to identify respective keys. */
81const int iCapsLockPosition = 30;
82const int iNumLockPosition = 90;
83const int iScrollLockPosition = 125;
84
85/** Set a generous file size limit. */
86const qint64 iFileSizeLimit = _256K;
87const QString strSubDirectorName("keyboardLayouts");
88
89/** Name, background color, normal font color, hover color, edited button background color, pressed button font color. */
90const char* predefinedColorThemes[][6] = {{"Clear Night","#000000", "#ffffff", "#859900", "#9b6767", "#000000"},
91 {"Gobi Dark","#002b36", "#fdf6e3", "#859900", "#cb4b16", "#002b36"},
92 {"Gobi Light","#fdf6e3", "#002b36", "#2aa198", "#cb4b16", "#bf4040"},
93 {0, 0, 0, 0, 0, 0}};
94
95typedef QPair<QLabel*, UISoftKeyboardColorButton*> ColorSelectLabelButton;
96
97enum KeyState
98{
99 KeyState_NotPressed,
100 KeyState_Pressed,
101 KeyState_Locked,
102 KeyState_Max
103};
104
105enum KeyType
106{
107 /** Can be in KeyState_NotPressed and KeyState_Pressed states. */
108 KeyType_Ordinary,
109 /** e.g. CapsLock, NumLock. Can be only in KeyState_NotPressed, KeyState_Locked */
110 KeyType_Lock,
111 /** e.g. Shift Can be in all 3 states*/
112 KeyType_Modifier,
113 KeyType_Max
114};
115
116enum KeyboardColorType
117{
118 KeyboardColorType_Background = 0,
119 KeyboardColorType_Font,
120 KeyboardColorType_Hover,
121 KeyboardColorType_Edit,
122 KeyboardColorType_Pressed,
123 KeyboardColorType_Max
124};
125
126enum KeyboardRegion
127{
128 KeyboardRegion_Main = 0,
129 KeyboardRegion_NumPad,
130 KeyboardRegion_MultimediaKeys,
131 KeyboardRegion_Max
132};
133
134struct UIKeyCaptions
135{
136 UIKeyCaptions(const QString &strBase, const QString &strShift,
137 const QString &strAltGr, const QString &strShiftAltGr)
138 : m_strBase(strBase)
139 , m_strShift(strShift)
140 , m_strAltGr(strAltGr)
141 , m_strShiftAltGr(strShiftAltGr)
142 {
143 m_strBase.replace("\\n", "\n");
144 m_strShift.replace("\\n", "\n");
145 m_strAltGr.replace("\\n", "\n");
146 m_strShiftAltGr.replace("\\n", "\n");
147 }
148 UIKeyCaptions(){}
149 bool operator==(const UIKeyCaptions &other) const
150 {
151 return (m_strBase == other.m_strBase &&
152 m_strShift == other.m_strShift &&
153 m_strAltGr == other.m_strAltGr &&
154 m_strShiftAltGr == other.m_strShiftAltGr);
155 }
156 QString m_strBase;
157 QString m_strShift;
158 QString m_strAltGr;
159 QString m_strShiftAltGr;
160};
161
162/** Returns a QPointF which lies on the line [p0, p1] and with a distance @p fDistance to p0. */
163static QPointF pointInBetween(qreal fDistance, const QPointF &p0, const QPointF &p1)
164{
165 QPointF vectorP0P1 = p1 - p0;
166 qreal length = sqrt(vectorP0P1.x() * vectorP0P1.x() + vectorP0P1.y() * vectorP0P1.y());
167 if (length == 0)
168 return QPointF();
169 /* Normalize the vector and add it to starting point: */
170 vectorP0P1 = (fDistance / length) * vectorP0P1 + p0;
171 return vectorP0P1;
172}
173
174
175/*********************************************************************************************************************************
176* UISoftKeyboardColorButton definition. *
177*********************************************************************************************************************************/
178
179class UISoftKeyboardColorButton : public QPushButton
180{
181 Q_OBJECT;
182
183public:
184
185 UISoftKeyboardColorButton(KeyboardColorType enmColorType, QWidget *pParent = 0);
186 KeyboardColorType colorType() const;
187
188public:
189
190 KeyboardColorType m_enmColorType;
191};
192
193
194/*********************************************************************************************************************************
195* UISoftKeyboardPhysicalLayout definition. *
196*********************************************************************************************************************************/
197
198/** This class is used to represent the physical layout of a keyboard (in contrast to UISoftKeyboardLayout).
199 * Physical layouts are read from an xml file where keys are placed in rows. Each UISoftKeyboardLayout must refer to a
200 * refer to a UISoftKeyboardPhysicalLayout instance. An example of an UISoftKeyboardPhysicalLayout instance is 103 key ISO layout.*/
201class UISoftKeyboardPhysicalLayout
202{
203
204public:
205 UISoftKeyboardPhysicalLayout();
206
207 void setName(const QString &strName);
208 const QString &name() const;
209
210 void setFileName(const QString &strName);
211 const QString &fileName() const;
212
213 void setUid(const QUuid &uid);
214 const QUuid &uid() const;
215
216 const QVector<UISoftKeyboardRow> &rows() const;
217 QVector<UISoftKeyboardRow> &rows();
218
219 void setLockKey(int iKeyPosition, UISoftKeyboardKey *pKey);
220 void updateLockKeyStates(bool fCapsLockState, bool fNumLockState, bool fScrollLockState);
221 void reset();
222
223 void setDefaultKeyWidth(int iDefaultKeyWidth);
224 int defaultKeyWidth() const;
225
226 /** Returns the sum totalHeight() of all rows(). */
227 int totalHeight() const;
228
229private:
230
231 void updateLockKeyState(bool fLockState, UISoftKeyboardKey *pKey);
232 QString m_strFileName;
233 QUuid m_uId;
234 QString m_strName;
235 QVector<UISoftKeyboardRow> m_rows;
236 int m_iDefaultKeyWidth;
237 /** Scroll, Num, and Caps Lock keys' states are updated thru some API events. Thus we keep their pointers in a containter. */
238 QMap<int, UISoftKeyboardKey*> m_lockKeys;
239};
240
241/*********************************************************************************************************************************
242* UIKeyboardLayoutEditor definition. *
243*********************************************************************************************************************************/
244
245/** A QWidget extension thru which we can edit key captions, the physical layout of the keyboard, name of the layout etc. */
246class UIKeyboardLayoutEditor : public QWidget
247{
248 Q_OBJECT;
249
250signals:
251
252 void sigLayoutEdited();
253 void sigUIKeyCaptionsEdited(UISoftKeyboardKey* pKey);
254 void sigGoBackButton();
255
256public:
257
258 UIKeyboardLayoutEditor(QWidget *pParent = 0);
259 void setKey(UISoftKeyboardKey *pKey);
260 void setLayoutToEdit(UISoftKeyboardLayout *pLayout);
261 void setPhysicalLayoutList(const QVector<UISoftKeyboardPhysicalLayout> &physicalLayouts);
262 void reset();
263
264private slots:
265
266 void sltCaptionsUpdate();
267 void sltPhysicalLayoutChanged();
268 void sltLayoutNameChanged(const QString &strCaption);
269 void sltLayoutNativeNameChanged(const QString &strCaption);
270 void sltRetranslateUI();
271
272private:
273
274 void prepareObjects();
275 void prepareConnections();
276 QWidget *prepareKeyCaptionEditWidgets();
277 void resetKeyWidgets();
278 QGridLayout *m_pEditorLayout;
279 QToolButton *m_pGoBackButton;
280 QGroupBox *m_pSelectedKeyGroupBox;
281 QGroupBox *m_pCaptionEditGroupBox;
282 QComboBox *m_pPhysicalLayoutCombo;
283 QLabel *m_pTitleLabel;
284 QLabel *m_pPhysicalLayoutLabel;
285 QLabel *m_pLayoutNameLabel;
286 QLabel *m_pLayoutNativeNameLabel;
287 QLabel *m_pScanCodeLabel;
288 QLabel *m_pPositionLabel;
289 QLabel *m_pBaseCaptionLabel;
290 QLabel *m_pShiftCaptionLabel;
291 QLabel *m_pAltGrCaptionLabel;
292 QLabel *m_pShiftAltGrCaptionLabel;
293 QLineEdit *m_pLayoutNameEdit;
294 QLineEdit *m_pLayoutNativeNameEdit;
295 QLineEdit *m_pScanCodeEdit;
296 QLineEdit *m_pPositionEdit;
297 QLineEdit *m_pBaseCaptionEdit;
298 QLineEdit *m_pShiftCaptionEdit;
299 QLineEdit *m_pAltGrCaptionEdit;
300 QLineEdit *m_pShiftAltGrCaptionEdit;
301
302 /** The key which is being currently edited. Might be Null. */
303 UISoftKeyboardKey *m_pKey;
304 /** The layout which is being currently edited. */
305 UISoftKeyboardLayout *m_pLayout;
306};
307
308/*********************************************************************************************************************************
309* UILayoutSelector definition. *
310*********************************************************************************************************************************/
311
312class UILayoutSelector : public QWidget
313{
314
315 Q_OBJECT;
316
317signals:
318
319 void sigSaveLayout();
320 void sigCopyLayout();
321 void sigDeleteLayout();
322 void sigLayoutSelectionChanged(const QUuid &strSelectedLayoutUid);
323 void sigShowLayoutEditor();
324 void sigCloseLayoutList();
325
326public:
327
328 UILayoutSelector(QWidget *pParent = 0);
329 void setLayoutList(const QStringList &layoutNames, QList<QUuid> layoutIdList);
330 void setCurrentLayout(const QUuid &layoutUid);
331 void setCurrentLayoutIsEditable(bool fEditable);
332
333private slots:
334
335 void sltCurrentItemChanged(QListWidgetItem *pCurrent, QListWidgetItem *pPrevious);
336 void sltRetranslateUI();
337
338private:
339
340 void prepareObjects();
341
342 QListWidget *m_pLayoutListWidget;
343 QToolButton *m_pApplyLayoutButton;
344 QToolButton *m_pEditLayoutButton;
345 QToolButton *m_pCopyLayoutButton;
346 QToolButton *m_pSaveLayoutButton;
347 QToolButton *m_pDeleteLayoutButton;
348 QLabel *m_pTitleLabel;
349 QToolButton *m_pCloseButton;
350};
351
352/*********************************************************************************************************************************
353* UISoftKeyboardRow definition. *
354*********************************************************************************************************************************/
355
356/** UISoftKeyboardRow represents a row in the physical keyboard. The rows are read from a physical layout file and contained
357 * keys are added to rows in the order they appear in that file.*/
358class UISoftKeyboardRow
359{
360
361public:
362
363 UISoftKeyboardRow();
364
365 void setDefaultWidth(int iWidth);
366 int defaultWidth() const;
367
368 void setDefaultHeight(int iHeight);
369 int defaultHeight() const;
370
371 /* Return the sum of the maximum key height and m_iSpaceHeightAfter */
372 int totalHeight() const;
373
374 QVector<UISoftKeyboardKey> &keys();
375 const QVector<UISoftKeyboardKey> &keys() const;
376
377 void setSpaceHeightAfter(int iSpace);
378 int spaceHeightAfter() const;
379
380 int leftMargin() const;
381 void setLeftMargin(int iMargin);
382
383private:
384
385 /** Default width and height might be inherited from the layout and overwritten in row settings. */
386 int m_iDefaultWidth;
387 int m_iDefaultHeight;
388
389 QVector<UISoftKeyboardKey> m_keys;
390 int m_iSpaceHeightAfter;
391 /* The width of the empty space before the 1st key. */
392 int m_iLeftMargin;
393};
394
395/*********************************************************************************************************************************
396* UISoftKeyboardKey definition. *
397*********************************************************************************************************************************/
398
399/** UISoftKeyboardKey is a place holder for a keyboard key. Graphical key represantations are drawn according to this class.
400 * The position of a key within the physical layout is read from the layout file. Note that UISoftKeyboardKey usually does not have
401 * caption field(s). Captions are kept by UISoftKeyboardLayout since same keys may (and usually do) have different captions in
402 * different layouts. So called static captions are exceptions. They are defined in physical layout files and kept as member of
403 * UISoftKeyboardKey. When a static caption exits captions (if any) from the keyboard layout files are ignored. */
404class UISoftKeyboardKey
405{
406public:
407
408 UISoftKeyboardKey();
409
410 const QRect keyGeometry() const;
411 void setKeyGeometry(const QRect &rect);
412
413 void setWidth(int iWidth);
414 int width() const;
415
416 void setHeight(int iHeight);
417 int height() const;
418
419 void setScanCode(LONG scanCode);
420 LONG scanCode() const;
421
422 void addScanCodePrefix(LONG scanCode);
423
424 void setUsageId(LONG usageId);
425 void setUsagePage(LONG usagePage);
426 QPair<LONG, LONG> usagePageIdPair() const;
427
428 void setSpaceWidthAfter(int iSpace);
429 int spaceWidthAfter() const;
430
431 void setPosition(int iPosition);
432 int position() const;
433
434 void setType(KeyType enmType);
435 KeyType type() const;
436
437 KeyboardRegion keyboardRegion() const;
438 void setKeyboardRegion(KeyboardRegion enmRegion);
439
440 void setCutout(int iCorner, int iWidth, int iHeight);
441
442 KeyState state() const;
443 void setState(KeyState state);
444
445 void setStaticCaption(const QString &strCaption);
446 const QString &staticCaption() const;
447
448 void setImageByName(const QString &strCaption);
449 QPixmap image() const;
450
451 void setParentWidget(UISoftKeyboardWidget* pParent);
452 QVector<LONG> scanCodeWithPrefix() const;
453
454 void setIsOSMenuKey(bool fFlag);
455 bool isOSMenuKey() const;
456
457 void release();
458 void press();
459
460 void setPoints(const QVector<QPointF> &points);
461 const QVector<QPointF> &points() const;
462 const QPainterPath &painterPath() const;
463
464
465 void setCornerRadius(float fCornerRadius);
466
467 QPolygonF polygonInGlobal() const;
468
469 int cutoutCorner() const;
470 int cutoutWidth() const;
471 int cutoutHeight() const;
472
473 void updateLockState(bool fLocked);
474 void reset();
475
476private:
477
478 void updateState(bool fPressed);
479 /** Creates a path out of points m_points with rounded corners. */
480 void computePainterPath();
481
482 QRect m_keyGeometry;
483 /** Stores the key points (vertices) in local coordinates. */
484 QVector<QPointF> m_points;
485 /** We cache the path since re-computing that at each draw is meaningless. */
486 QPainterPath m_painterPath;
487 KeyType m_enmType;
488 KeyState m_enmState;
489 /** Key width as it is read from the xml file. */
490 int m_iWidth;
491 /** Key height as it is read from the xml file. */
492 int m_iHeight;
493 int m_iSpaceWidthAfter;
494 LONG m_scanCode;
495 QVector<LONG> m_scanCodePrefix;
496
497 /** @name Cutouts are used to create non-rectangle keys polygons.
498 * @{ */
499 int m_iCutoutWidth;
500 int m_iCutoutHeight;
501 /** -1 is for no cutout. 0 is the topleft, 2 is the top right and so on. */
502 int m_iCutoutCorner;
503 /** @} */
504
505 /** Key's position in the layout. */
506 int m_iPosition;
507 UISoftKeyboardWidget *m_pParentWidget;
508 LONG m_iUsageId;
509 LONG m_iUsagePage;
510 KeyboardRegion m_enmKeyboardRegion;
511 /** This is used for multimedia keys, OS key etc where we want to have a non-modifiable
512 * caption (usually a single char). This caption is defined in the physical layout file
513 * and has precedence over the captions defined in keyboard layout files. */
514 QString m_strStaticCaption;
515 bool m_fIsOSMenuKey;
516 double m_fCornerRadius;
517 QIcon m_icon;
518};
519
520
521/*********************************************************************************************************************************
522* UISoftKeyboardLayout definition. *
523*********************************************************************************************************************************/
524/** UISoftKeyboardLayout represents mainly a set of captions for the keys. It refers to a phsical layout which defines the
525 * positioning and number of keys (alongside with scan codes etc.). UISoftKeyboardLayout instances are read from xml files. An
526 * example for UISoftKeyboardLayout instance is 'US International' keyboard layout. */
527class UISoftKeyboardLayout
528{
529
530public:
531
532 UISoftKeyboardLayout();
533
534 void setName(const QString &strName);
535 const QString &name() const;
536
537 void setNativeName(const QString &strLocaName);
538 const QString &nativeName() const;
539
540 /** Combines name and native name and returns the string. */
541 QString nameString() const;
542
543 void setSourceFilePath(const QString& strSourceFilePath);
544 const QString& sourceFilePath() const;
545
546 void setIsFromResources(bool fIsFromResources);
547 bool isFromResources() const;
548
549 void setEditable(bool fEditable);
550 bool editable() const;
551
552 void setPhysicalLayoutUuid(const QUuid &uuid);
553 const QUuid &physicalLayoutUuid() const;
554
555 void addOrUpdateUIKeyCaptions(int iKeyPosition, const UIKeyCaptions &keyCaptions);
556 UIKeyCaptions keyCaptions(int iKeyPosition) const;
557
558 bool operator==(const UISoftKeyboardLayout &otherLayout) const;
559
560 QString baseCaption(int iKeyPosition) const;
561 QString shiftCaption(int iKeyPosition) const;
562
563 QString altGrCaption(int iKeyPosition) const;
564 QString shiftAltGrCaption(int iKeyPosition) const;
565
566 void setEditedBuNotSaved(bool fEditedButNotsaved);
567 bool editedButNotSaved() const;
568
569 void setUid(const QUuid &uid);
570 QUuid uid() const;
571
572 void drawTextInRect(const UISoftKeyboardKey &key, QPainter &painter);
573 void drawKeyImageInRect(const UISoftKeyboardKey &key, QPainter &painter);
574
575private:
576
577 QMap<int, UIKeyCaptions> m_keyCaptionsMap;
578 /** Caching the font sizes we used for font rendering since it is not a very cheap process to compute these. */
579 QMap<int, int> m_keyCaptionsFontSizeMap;
580 /** The UUID of the physical layout used by this layout. */
581 QUuid m_physicalLayoutUuid;
582 /** This is the English name of the layout. */
583 QString m_strName;
584 QString m_strNativeName;
585 QString m_strSourceFilePath;
586 bool m_fEditable;
587 bool m_fIsFromResources;
588 bool m_fEditedButNotSaved;
589 QUuid m_uid;
590};
591
592/*********************************************************************************************************************************
593* UISoftKeyboardColorTheme definition. *
594*********************************************************************************************************************************/
595
596class UISoftKeyboardColorTheme
597{
598
599public:
600
601 UISoftKeyboardColorTheme();
602 UISoftKeyboardColorTheme(const QString &strName,
603 const QString &strBackgroundColor,
604 const QString &strNormalFontColor,
605 const QString &strHoverColor,
606 const QString &strEditedButtonBackgroundColor,
607 const QString &strPressedButtonFontColor);
608
609 void setColor(KeyboardColorType enmColorType, const QColor &color);
610 QColor color(KeyboardColorType enmColorType) const;
611 QStringList colorsToStringList() const;
612 void colorsFromStringList(const QStringList &colorStringList);
613
614 const QString &name() const;
615 void setName(const QString &strName);
616
617 bool isEditable() const;
618 void setIsEditable(bool fIsEditable);
619
620private:
621
622 QVector<QColor> m_colors;
623 QString m_strName;
624 bool m_fIsEditable;
625};
626
627/*********************************************************************************************************************************
628* UISoftKeyboardWidget definition. *
629*********************************************************************************************************************************/
630
631/** The container widget for keyboard keys. It also handles all the keyboard related events. paintEvent of this class
632 * handles drawing of the soft keyboard. */
633class UISoftKeyboardWidget : public QWidget
634{
635 Q_OBJECT;
636
637 enum Mode
638 {
639 Mode_LayoutEdit,
640 Mode_Keyboard,
641 Mode_Max
642 };
643
644signals:
645
646 void sigStatusBarMessage(const QString &strMessage);
647 void sigCurrentLayoutChange();
648 void sigKeyToEdit(UISoftKeyboardKey* pKey);
649 void sigCurrentColorThemeChanged();
650 void sigOptionsChanged();
651
652public:
653
654 UISoftKeyboardWidget(QWidget *pParent, UIMachine *pMachine);
655
656 virtual QSize minimumSizeHint() const RT_OVERRIDE;
657 virtual QSize sizeHint() const RT_OVERRIDE;
658 void keyStateChange(UISoftKeyboardKey* pKey);
659 void loadLayouts();
660
661 void setCurrentLayout(const QUuid &layoutUid);
662 UISoftKeyboardLayout *currentLayout();
663
664 QStringList layoutNameList() const;
665 QList<QUuid> layoutUidList() const;
666 const QVector<UISoftKeyboardPhysicalLayout> &physicalLayouts() const;
667 void deleteCurrentLayout();
668 void toggleEditMode(bool fIsEditMode);
669
670 void saveCurentLayoutToFile();
671 void copyCurentLayout();
672 float layoutAspectRatio();
673
674 bool hideOSMenuKeys() const;
675 void setHideOSMenuKeys(bool fHide);
676
677 bool hideNumPad() const;
678 void setHideNumPad(bool fHide);
679
680 bool hideMultimediaKeys() const;
681 void setHideMultimediaKeys(bool fHide);
682
683 QColor color(KeyboardColorType enmColorType) const;
684 void setColor(KeyboardColorType ennmColorType, const QColor &color);
685
686 QStringList colorsToStringList(const QString &strColorThemeName);
687 void colorsFromStringList(const QString &strColorThemeName, const QStringList &colorStringList);
688
689 /** Unlike modifier and ordinary keys we update the state of the Lock keys thru event signals we receieve
690 * from the guest OS. Parameter f???State is true if the corresponding key is locked. */
691 void updateLockKeyStates(bool fCapsLockState, bool fNumLockState, bool fScrollLockState);
692 void reset();
693
694 QStringList colorThemeNames() const;
695 QString currentColorThemeName() const;
696 void setColorThemeByName(const QString &strColorThemeName);
697 void parentDialogDeactivated();
698 bool isColorThemeEditable() const;
699 /** Returns a list of layout names that have been edited but not yet saved to a file. */
700 QStringList unsavedLayoutsNameList() const;
701
702protected:
703
704 virtual void paintEvent(QPaintEvent *pEvent) RT_OVERRIDE;
705 virtual void mousePressEvent(QMouseEvent *pEvent) RT_OVERRIDE;
706 virtual void mouseReleaseEvent(QMouseEvent *pEvent) RT_OVERRIDE;
707 virtual void mouseMoveEvent(QMouseEvent *pEvent) RT_OVERRIDE;
708
709private slots:
710
711 void sltKeyboardLedsChange();
712 void sltRetranslateUI();
713
714private:
715
716 void addLayout(const UISoftKeyboardLayout &newLayout);
717 void setNewMinimumSize(const QSize &size);
718 void setInitialSize(int iWidth, int iHeight);
719 /** Searches for the key which contains the position of the @p pEvent and returns it if found. */
720 UISoftKeyboardKey *keyUnderMouse(QMouseEvent *pEvent);
721 UISoftKeyboardKey *keyUnderMouse(const QPoint &point);
722 void handleKeyPress(UISoftKeyboardKey *pKey);
723 void handleKeyRelease(UISoftKeyboardKey *pKey);
724 /** Sends usage id/page to API when a modifier key is right clicked. useful for testing and things like
725 * Window key press for start menu opening. This works orthogonal to left clicks.*/
726 void modifierKeyPressRelease(UISoftKeyboardKey *pKey, bool fRelease);
727 bool loadPhysicalLayout(const QString &strLayoutFileName, KeyboardRegion keyboardRegion = KeyboardRegion_Main);
728 bool loadKeyboardLayout(const QString &strLayoutName);
729 void prepareObjects();
730 void prepareColorThemes();
731 UISoftKeyboardPhysicalLayout *findPhysicalLayout(const QUuid &uuid);
732 /** Sets m_pKeyBeingEdited. */
733 void setKeyBeingEdited(UISoftKeyboardKey *pKey);
734 bool layoutByNameExists(const QString &strName) const;
735
736 /** Looks under the default keyboard layout folder and add the file names to the fileList. */
737 void lookAtDefaultLayoutFolder(QStringList &fileList);
738 UISoftKeyboardColorTheme *colorTheme(const QString &strColorThemeName);
739 void showKeyTooltip(UISoftKeyboardKey *pKey);
740 void putKeyboardSequence(QVector<LONG> sequence);
741 void putUsageCodesPress(QVector<QPair<LONG, LONG> > sequence);
742 void putUsageCodesRelease(QVector<QPair<LONG, LONG> > sequence);
743
744 UIMachine *m_pMachine;
745 UISoftKeyboardKey *m_pKeyUnderMouse;
746 UISoftKeyboardKey *m_pKeyBeingEdited;
747
748 UISoftKeyboardKey *m_pKeyPressed;
749 UISoftKeyboardColorTheme *m_currentColorTheme;
750 QVector<UISoftKeyboardColorTheme> m_colorThemes;
751 QVector<UISoftKeyboardKey*> m_pressedModifiers;
752 QVector<UISoftKeyboardPhysicalLayout> m_physicalLayouts;
753 UISoftKeyboardPhysicalLayout m_numPadLayout;
754 UISoftKeyboardPhysicalLayout m_multiMediaKeysLayout;
755 QMap<QUuid, UISoftKeyboardLayout> m_layouts;
756 QUuid m_uCurrentLayoutId;
757 /** Key is the key position as read from the layout and value is the message we show as mouse hovers over the key. */
758 QMap<int, QString> m_keyTooltips;
759
760 QSize m_minimumSize;
761 float m_fScaleFactorX;
762 float m_fScaleFactorY;
763 int m_iInitialHeight;
764 /** This is the width of the keyboard including the numpad but without m_iInitialWidthNoNumPad */
765 int m_iInitialWidth;
766 int m_iInitialWidthNoNumPad;
767 /** This widt is added while drawing the keyboard not to key geometries. */
768 int m_iBeforeNumPadWidth;
769 int m_iXSpacing;
770 int m_iYSpacing;
771 int m_iLeftMargin;
772 int m_iTopMargin;
773 int m_iRightMargin;
774 int m_iBottomMargin;
775 Mode m_enmMode;
776 bool m_fHideOSMenuKeys;
777 bool m_fHideNumPad;
778 bool m_fHideMultimediaKeys;
779};
780
781/*********************************************************************************************************************************
782* UIPhysicalLayoutReader definition. *
783*********************************************************************************************************************************/
784
785class UIPhysicalLayoutReader
786{
787
788public:
789
790 bool parseXMLFile(const QString &strFileName, UISoftKeyboardPhysicalLayout &physicalLayout);
791 static QVector<QPointF> computeKeyVertices(const UISoftKeyboardKey &key);
792
793private:
794
795 void parseKey(UISoftKeyboardRow &row);
796 void parseRow(int iDefaultWidth, int iDefaultHeight, QVector<UISoftKeyboardRow> &rows);
797 /** Parses the horizontal space between keys. */
798 void parseKeySpace(UISoftKeyboardRow &row);
799 void parseCutout(UISoftKeyboardKey &key);
800
801 QXmlStreamReader m_xmlReader;
802};
803
804/*********************************************************************************************************************************
805* UIKeyboardLayoutReader definition. *
806*********************************************************************************************************************************/
807
808class UIKeyboardLayoutReader
809{
810
811public:
812
813 bool parseFile(const QString &strFileName, UISoftKeyboardLayout &layout);
814
815private:
816
817 void parseKey(UISoftKeyboardLayout &layout);
818 QXmlStreamReader m_xmlReader;
819 /** Map key is the key position and the value is the captions of the key. */
820};
821
822
823/*********************************************************************************************************************************
824* UISoftKeyboardStatusBarWidget definition. *
825*********************************************************************************************************************************/
826
827class UISoftKeyboardStatusBarWidget : public QWidget
828{
829 Q_OBJECT;
830
831signals:
832
833 void sigShowHideSidePanel();
834 void sigShowSettingWidget();
835 void sigResetKeyboard();
836 void sigHelpButtonPressed();
837
838public:
839
840 UISoftKeyboardStatusBarWidget(QWidget *pParent = 0);
841 void updateLayoutNameInStatusBar(const QString &strMessage);
842
843private slots:
844
845 void sltRetranslateUI();
846
847private:
848
849 void prepareObjects();
850 QToolButton *m_pLayoutListButton;
851 QToolButton *m_pSettingsButton;
852 QToolButton *m_pResetButton;
853 QToolButton *m_pHelpButton;
854 QLabel *m_pMessageLabel;
855};
856
857
858/*********************************************************************************************************************************
859* UISoftKeyboardSettingsWidget definition. *
860*********************************************************************************************************************************/
861
862class UISoftKeyboardSettingsWidget : public QWidget
863{
864 Q_OBJECT;
865
866signals:
867
868 void sigHideNumPad(bool fHide);
869 void sigHideOSMenuKeys(bool fHide);
870 void sigHideMultimediaKeys(bool fHide);
871 void sigColorCellClicked(int iColorRow);
872 void sigCloseSettingsWidget();
873 void sigColorThemeSelectionChanged(const QString &strColorThemeName);
874
875public:
876
877 UISoftKeyboardSettingsWidget(QWidget *pParent = 0);
878 void setHideOSMenuKeys(bool fHide);
879 void setHideNumPad(bool fHide);
880 void setHideMultimediaKeys(bool fHide);
881 void setColorSelectionButtonBackgroundAndTooltip(KeyboardColorType enmColorType, const QColor &color, bool fIsColorEditable);
882 void setColorThemeNames(const QStringList &colorThemeNames);
883 void setCurrentColorThemeName(const QString &strColorThemeName);
884
885private slots:
886
887 void sltColorSelectionButtonClicked();
888 void sltRetranslateUI();
889
890private:
891
892 void prepareObjects();
893
894 QCheckBox *m_pHideNumPadCheckBox;
895 QCheckBox *m_pShowOsMenuButtonsCheckBox;
896 QCheckBox *m_pHideMultimediaKeysCheckBox;
897 QGroupBox *m_pColorThemeGroupBox;
898 QComboBox *m_pColorThemeComboBox;
899 QLabel *m_pTitleLabel;
900 QToolButton *m_pCloseButton;
901 QVector<ColorSelectLabelButton> m_colorSelectLabelsButtons;
902};
903
904
905/*********************************************************************************************************************************
906* UISoftKeyboardColorButton implementation. *
907*********************************************************************************************************************************/
908
909
910UISoftKeyboardColorButton::UISoftKeyboardColorButton(KeyboardColorType enmColorType, QWidget *pParent /*= 0 */)
911 :QPushButton(pParent)
912 , m_enmColorType(enmColorType){}
913
914KeyboardColorType UISoftKeyboardColorButton::colorType() const
915{
916 return m_enmColorType;
917}
918
919
920/*********************************************************************************************************************************
921* UISoftKeyboardPhysicalLayout implementation. *
922*********************************************************************************************************************************/
923
924UISoftKeyboardPhysicalLayout::UISoftKeyboardPhysicalLayout()
925 :m_iDefaultKeyWidth(50)
926{
927}
928
929void UISoftKeyboardPhysicalLayout::setName(const QString &strName)
930{
931 m_strName = strName;
932}
933
934const QString &UISoftKeyboardPhysicalLayout::name() const
935{
936 return m_strName;
937}
938
939void UISoftKeyboardPhysicalLayout::setFileName(const QString &strName)
940{
941 m_strFileName = strName;
942}
943
944const QString &UISoftKeyboardPhysicalLayout::fileName() const
945{
946 return m_strFileName;
947}
948
949void UISoftKeyboardPhysicalLayout::setUid(const QUuid &uid)
950{
951 m_uId = uid;
952}
953
954const QUuid &UISoftKeyboardPhysicalLayout::uid() const
955{
956 return m_uId;
957}
958
959const QVector<UISoftKeyboardRow> &UISoftKeyboardPhysicalLayout::rows() const
960{
961 return m_rows;
962}
963
964QVector<UISoftKeyboardRow> &UISoftKeyboardPhysicalLayout::rows()
965{
966 return m_rows;
967}
968
969void UISoftKeyboardPhysicalLayout::setLockKey(int iKeyPosition, UISoftKeyboardKey *pKey)
970{
971 m_lockKeys[iKeyPosition] = pKey;
972}
973
974void UISoftKeyboardPhysicalLayout::updateLockKeyStates(bool fCapsLockState, bool fNumLockState, bool fScrollLockState)
975{
976 updateLockKeyState(fCapsLockState, m_lockKeys.value(iCapsLockPosition, 0));
977 updateLockKeyState(fNumLockState, m_lockKeys.value(iNumLockPosition, 0));
978 updateLockKeyState(fScrollLockState, m_lockKeys.value(iScrollLockPosition, 0));
979}
980
981void UISoftKeyboardPhysicalLayout::setDefaultKeyWidth(int iDefaultKeyWidth)
982{
983 m_iDefaultKeyWidth = iDefaultKeyWidth;
984}
985
986int UISoftKeyboardPhysicalLayout::defaultKeyWidth() const
987{
988 return m_iDefaultKeyWidth;
989}
990
991void UISoftKeyboardPhysicalLayout::reset()
992{
993 for (int i = 0; i < m_rows.size(); ++i)
994 {
995 for (int j = 0; j < m_rows[i].keys().size(); ++j)
996 {
997 m_rows[i].keys()[j].reset();
998 }
999 }
1000}
1001
1002int UISoftKeyboardPhysicalLayout::totalHeight() const
1003{
1004 int iHeight = 0;
1005 for (int i = 0; i < m_rows.size(); ++i)
1006 iHeight += m_rows[i].totalHeight();
1007 return iHeight;
1008}
1009
1010void UISoftKeyboardPhysicalLayout::updateLockKeyState(bool fLockState, UISoftKeyboardKey *pKey)
1011{
1012 if (!pKey)
1013 return;
1014 pKey->updateLockState(fLockState);
1015}
1016
1017/*********************************************************************************************************************************
1018* UIKeyboardLayoutEditor implementation. *
1019*********************************************************************************************************************************/
1020
1021UIKeyboardLayoutEditor::UIKeyboardLayoutEditor(QWidget *pParent /* = 0 */)
1022 : QWidget(pParent)
1023 , m_pEditorLayout(0)
1024 , m_pGoBackButton(0)
1025 , m_pSelectedKeyGroupBox(0)
1026 , m_pCaptionEditGroupBox(0)
1027 , m_pPhysicalLayoutCombo(0)
1028 , m_pTitleLabel(0)
1029 , m_pPhysicalLayoutLabel(0)
1030 , m_pLayoutNameLabel(0)
1031 , m_pLayoutNativeNameLabel(0)
1032 , m_pScanCodeLabel(0)
1033 , m_pPositionLabel(0)
1034 , m_pBaseCaptionLabel(0)
1035 , m_pShiftCaptionLabel(0)
1036 , m_pAltGrCaptionLabel(0)
1037 , m_pShiftAltGrCaptionLabel(0)
1038 , m_pLayoutNameEdit(0)
1039 , m_pLayoutNativeNameEdit(0)
1040 , m_pScanCodeEdit(0)
1041 , m_pPositionEdit(0)
1042 , m_pBaseCaptionEdit(0)
1043 , m_pShiftCaptionEdit(0)
1044 , m_pAltGrCaptionEdit(0)
1045 , m_pShiftAltGrCaptionEdit(0)
1046 , m_pKey(0)
1047 , m_pLayout(0)
1048{
1049 setAutoFillBackground(true);
1050 prepareObjects();
1051}
1052
1053void UIKeyboardLayoutEditor::setKey(UISoftKeyboardKey *pKey)
1054{
1055 if (m_pKey == pKey || !m_pLayout)
1056 return;
1057 /* First apply the pending changes to the key that has been edited: */
1058 if (m_pKey)
1059 {
1060 UIKeyCaptions captions = m_pLayout->keyCaptions(m_pKey->position());
1061 if (captions.m_strBase != m_pBaseCaptionEdit->text() ||
1062 captions.m_strShift != m_pShiftCaptionEdit->text() ||
1063 captions.m_strAltGr != m_pAltGrCaptionEdit->text() ||
1064 captions.m_strShiftAltGr != m_pShiftAltGrCaptionEdit->text())
1065 m_pLayout->addOrUpdateUIKeyCaptions(m_pKey->position(),
1066 UIKeyCaptions(m_pBaseCaptionEdit->text(),
1067 m_pShiftCaptionEdit->text(),
1068 m_pAltGrCaptionEdit->text(),
1069 m_pShiftAltGrCaptionEdit->text()));
1070 }
1071 m_pKey = pKey;
1072 if (m_pSelectedKeyGroupBox)
1073 m_pSelectedKeyGroupBox->setEnabled(m_pKey);
1074 if (!m_pKey)
1075 {
1076 resetKeyWidgets();
1077 return;
1078 }
1079 if (m_pScanCodeEdit)
1080 m_pScanCodeEdit->setText(QString::number(m_pKey->scanCode(), 16));
1081 if (m_pPositionEdit)
1082 m_pPositionEdit->setText(QString::number(m_pKey->position()));
1083 UIKeyCaptions captions = m_pLayout->keyCaptions(m_pKey->position());
1084 if (m_pBaseCaptionEdit)
1085 m_pBaseCaptionEdit->setText(captions.m_strBase);
1086 if (m_pShiftCaptionEdit)
1087 m_pShiftCaptionEdit->setText(captions.m_strShift);
1088 if (m_pAltGrCaptionEdit)
1089 m_pAltGrCaptionEdit->setText(captions.m_strAltGr);
1090 if (m_pShiftAltGrCaptionEdit)
1091 m_pShiftAltGrCaptionEdit->setText(captions.m_strShiftAltGr);
1092 m_pBaseCaptionEdit->setFocus();
1093}
1094
1095void UIKeyboardLayoutEditor::setLayoutToEdit(UISoftKeyboardLayout *pLayout)
1096{
1097 if (m_pLayout == pLayout)
1098 return;
1099
1100 m_pLayout = pLayout;
1101 if (!m_pLayout)
1102 reset();
1103
1104 if (m_pLayoutNameEdit)
1105 m_pLayoutNameEdit->setText(m_pLayout ? m_pLayout->name() : QString());
1106
1107 if (m_pLayoutNativeNameEdit)
1108 m_pLayoutNativeNameEdit->setText(m_pLayout ? m_pLayout->nativeName() : QString());
1109
1110 if (m_pPhysicalLayoutCombo && m_pLayout)
1111 {
1112 int iIndex = m_pPhysicalLayoutCombo->findData(m_pLayout->physicalLayoutUuid());
1113 if (iIndex != -1)
1114 m_pPhysicalLayoutCombo->setCurrentIndex(iIndex);
1115 }
1116 update();
1117}
1118
1119void UIKeyboardLayoutEditor::setPhysicalLayoutList(const QVector<UISoftKeyboardPhysicalLayout> &physicalLayouts)
1120{
1121 if (!m_pPhysicalLayoutCombo)
1122 return;
1123 m_pPhysicalLayoutCombo->clear();
1124 foreach (const UISoftKeyboardPhysicalLayout &physicalLayout, physicalLayouts)
1125 m_pPhysicalLayoutCombo->addItem(physicalLayout.name(), physicalLayout.uid());
1126}
1127
1128void UIKeyboardLayoutEditor::sltCaptionsUpdate()
1129{
1130 if (!m_pKey || !m_pLayout)
1131 return;
1132 m_pLayout->addOrUpdateUIKeyCaptions(m_pKey->position(),
1133 UIKeyCaptions(m_pBaseCaptionEdit->text(),
1134 m_pShiftCaptionEdit->text(),
1135 m_pAltGrCaptionEdit->text(),
1136 m_pShiftAltGrCaptionEdit->text()));
1137 emit sigUIKeyCaptionsEdited(m_pKey);
1138}
1139
1140void UIKeyboardLayoutEditor::sltPhysicalLayoutChanged()
1141{
1142 if (!m_pPhysicalLayoutCombo || !m_pLayout)
1143 return;
1144 QUuid currentData = m_pPhysicalLayoutCombo->currentData().toUuid();
1145 if (!currentData.isNull())
1146 m_pLayout->setPhysicalLayoutUuid(currentData);
1147 emit sigLayoutEdited();
1148}
1149
1150void UIKeyboardLayoutEditor::sltLayoutNameChanged(const QString &strName)
1151{
1152 if (!m_pLayout || m_pLayout->name() == strName)
1153 return;
1154 m_pLayout->setName(strName);
1155 emit sigLayoutEdited();
1156}
1157
1158void UIKeyboardLayoutEditor::sltLayoutNativeNameChanged(const QString &strNativeName)
1159{
1160 if (!m_pLayout || m_pLayout->nativeName() == strNativeName)
1161 return;
1162 m_pLayout->setNativeName(strNativeName);
1163 emit sigLayoutEdited();
1164}
1165
1166void UIKeyboardLayoutEditor::sltRetranslateUI()
1167{
1168 if (m_pTitleLabel)
1169 m_pTitleLabel->setText(UISoftKeyboard::tr("Layout Editor"));
1170 if (m_pGoBackButton)
1171 {
1172 m_pGoBackButton->setToolTip(UISoftKeyboard::tr("Return Back to Layout List"));
1173 m_pGoBackButton->setText(UISoftKeyboard::tr("Back to Layout List"));
1174 }
1175 if (m_pPhysicalLayoutLabel)
1176 m_pPhysicalLayoutLabel->setText(UISoftKeyboard::tr("Physical Layout"));
1177 if (m_pLayoutNameLabel)
1178 m_pLayoutNameLabel->setText(UISoftKeyboard::tr("English Name"));
1179 if (m_pLayoutNameEdit)
1180 m_pLayoutNameEdit->setToolTip(UISoftKeyboard::tr("Name of the Layout in English"));
1181 if (m_pLayoutNativeNameLabel)
1182 m_pLayoutNativeNameLabel->setText(UISoftKeyboard::tr("Native Language Name"));
1183 if (m_pLayoutNativeNameEdit)
1184 m_pLayoutNativeNameEdit->setToolTip(UISoftKeyboard::tr("Name of the Layout in the native Language"));
1185 if (m_pScanCodeLabel)
1186 m_pScanCodeLabel->setText(UISoftKeyboard::tr("Scan Code"));
1187 if (m_pScanCodeEdit)
1188 m_pScanCodeEdit->setToolTip(UISoftKeyboard::tr("The scan code the key produces. Not editable"));
1189 if (m_pPositionLabel)
1190 m_pPositionLabel->setText(UISoftKeyboard::tr("Position"));
1191 if (m_pPositionEdit)
1192 m_pPositionEdit->setToolTip(UISoftKeyboard::tr("The physical position of the key. Not editable"));
1193 if (m_pBaseCaptionLabel)
1194 m_pBaseCaptionLabel->setText(UISoftKeyboard::tr("Base"));
1195 if (m_pShiftCaptionLabel)
1196 m_pShiftCaptionLabel->setText(UISoftKeyboard::tr("Shift"));
1197 if (m_pAltGrCaptionLabel)
1198 m_pAltGrCaptionLabel->setText(UISoftKeyboard::tr("AltGr"));
1199 if (m_pShiftAltGrCaptionLabel)
1200 m_pShiftAltGrCaptionLabel->setText(UISoftKeyboard::tr("ShiftAltGr"));
1201 if (m_pCaptionEditGroupBox)
1202 m_pCaptionEditGroupBox->setTitle(UISoftKeyboard::tr("Captions"));
1203 if (m_pSelectedKeyGroupBox)
1204 m_pSelectedKeyGroupBox->setTitle(UISoftKeyboard::tr("Selected Key"));
1205}
1206
1207void UIKeyboardLayoutEditor::prepareObjects()
1208{
1209 m_pEditorLayout = new QGridLayout;
1210 if (!m_pEditorLayout)
1211 return;
1212 setLayout(m_pEditorLayout);
1213
1214 QHBoxLayout *pTitleLayout = new QHBoxLayout;
1215 m_pGoBackButton = new QToolButton;
1216 m_pGoBackButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
1217 m_pGoBackButton->setIcon(UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_ArrowBack));
1218 m_pGoBackButton->setAutoRaise(true);
1219 m_pEditorLayout->addWidget(m_pGoBackButton, 0, 0, 1, 1);
1220 connect(m_pGoBackButton, &QToolButton::clicked, this, &UIKeyboardLayoutEditor::sigGoBackButton);
1221 m_pTitleLabel = new QLabel;
1222 pTitleLayout->addWidget(m_pTitleLabel);
1223 pTitleLayout->addStretch(2);
1224 pTitleLayout->addWidget(m_pGoBackButton);
1225 m_pEditorLayout->addLayout(pTitleLayout, 0, 0, 1, 2);
1226
1227 m_pLayoutNativeNameLabel = new QLabel;
1228 m_pLayoutNativeNameEdit = new QLineEdit;
1229 m_pLayoutNativeNameLabel->setBuddy(m_pLayoutNativeNameEdit);
1230 m_pEditorLayout->addWidget(m_pLayoutNativeNameLabel, 2, 0, 1, 1);
1231 m_pEditorLayout->addWidget(m_pLayoutNativeNameEdit, 2, 1, 1, 1);
1232 connect(m_pLayoutNativeNameEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltLayoutNativeNameChanged);
1233
1234 m_pLayoutNameLabel = new QLabel;
1235 m_pLayoutNameEdit = new QLineEdit;
1236 m_pLayoutNameLabel->setBuddy(m_pLayoutNameEdit);
1237 m_pEditorLayout->addWidget(m_pLayoutNameLabel, 3, 0, 1, 1);
1238 m_pEditorLayout->addWidget(m_pLayoutNameEdit, 3, 1, 1, 1);
1239 connect(m_pLayoutNameEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltLayoutNameChanged);
1240
1241
1242 m_pPhysicalLayoutLabel = new QLabel;
1243 m_pPhysicalLayoutCombo = new QComboBox;
1244 m_pPhysicalLayoutLabel->setBuddy(m_pPhysicalLayoutCombo);
1245 m_pEditorLayout->addWidget(m_pPhysicalLayoutLabel, 4, 0, 1, 1);
1246 m_pEditorLayout->addWidget(m_pPhysicalLayoutCombo, 4, 1, 1, 1);
1247 connect(m_pPhysicalLayoutCombo, &QComboBox::currentIndexChanged, this, &UIKeyboardLayoutEditor::sltPhysicalLayoutChanged);
1248
1249 m_pSelectedKeyGroupBox = new QGroupBox;
1250 m_pSelectedKeyGroupBox->setEnabled(false);
1251
1252 m_pEditorLayout->addWidget(m_pSelectedKeyGroupBox, 5, 0, 1, 2);
1253 QGridLayout *pSelectedKeyLayout = new QGridLayout(m_pSelectedKeyGroupBox);
1254 pSelectedKeyLayout->setSpacing(0);
1255 pSelectedKeyLayout->setContentsMargins(0, 0, 0, 0);
1256
1257 m_pScanCodeLabel = new QLabel;
1258 m_pScanCodeEdit = new QLineEdit;
1259 m_pScanCodeLabel->setBuddy(m_pScanCodeEdit);
1260 m_pScanCodeEdit->setEnabled(false);
1261 pSelectedKeyLayout->addWidget(m_pScanCodeLabel, 0, 0);
1262 pSelectedKeyLayout->addWidget(m_pScanCodeEdit, 0, 1);
1263
1264 m_pPositionLabel= new QLabel;
1265 m_pPositionEdit = new QLineEdit;
1266 m_pPositionEdit->setEnabled(false);
1267 m_pPositionLabel->setBuddy(m_pPositionEdit);
1268 pSelectedKeyLayout->addWidget(m_pPositionLabel, 1, 0);
1269 pSelectedKeyLayout->addWidget(m_pPositionEdit, 1, 1);
1270
1271 QWidget *pCaptionEditor = prepareKeyCaptionEditWidgets();
1272 if (pCaptionEditor)
1273 pSelectedKeyLayout->addWidget(pCaptionEditor, 2, 0, 2, 2);
1274
1275 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
1276 if (pSpacer)
1277 pSelectedKeyLayout->addItem(pSpacer, 4, 1);
1278
1279 sltRetranslateUI();
1280
1281 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
1282 this, &UIKeyboardLayoutEditor::sltRetranslateUI);
1283}
1284
1285QWidget *UIKeyboardLayoutEditor::prepareKeyCaptionEditWidgets()
1286{
1287 m_pCaptionEditGroupBox = new QGroupBox;
1288 if (!m_pCaptionEditGroupBox)
1289 return 0;
1290 m_pCaptionEditGroupBox->setFlat(false);
1291 QGridLayout *pCaptionEditorLayout = new QGridLayout(m_pCaptionEditGroupBox);
1292 pCaptionEditorLayout->setSpacing(0);
1293 pCaptionEditorLayout->setContentsMargins(0, 0, 0, 0);
1294
1295 if (!pCaptionEditorLayout)
1296 return 0;
1297
1298 m_pBaseCaptionLabel = new QLabel;
1299 m_pBaseCaptionEdit = new QLineEdit;
1300 m_pBaseCaptionLabel->setBuddy(m_pBaseCaptionEdit);
1301 pCaptionEditorLayout->addWidget(m_pBaseCaptionLabel, 0, 0);
1302 pCaptionEditorLayout->addWidget(m_pBaseCaptionEdit, 0, 1);
1303 connect(m_pBaseCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1304
1305 m_pShiftCaptionLabel = new QLabel;
1306 m_pShiftCaptionEdit = new QLineEdit;
1307 m_pShiftCaptionLabel->setBuddy(m_pShiftCaptionEdit);
1308 pCaptionEditorLayout->addWidget(m_pShiftCaptionLabel, 1, 0);
1309 pCaptionEditorLayout->addWidget(m_pShiftCaptionEdit, 1, 1);
1310 connect(m_pShiftCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1311
1312 m_pAltGrCaptionLabel = new QLabel;
1313 m_pAltGrCaptionEdit = new QLineEdit;
1314 m_pAltGrCaptionLabel->setBuddy(m_pAltGrCaptionEdit);
1315 pCaptionEditorLayout->addWidget(m_pAltGrCaptionLabel, 2, 0);
1316 pCaptionEditorLayout->addWidget(m_pAltGrCaptionEdit, 2, 1);
1317 connect(m_pAltGrCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1318
1319 m_pShiftAltGrCaptionLabel = new QLabel;
1320 m_pShiftAltGrCaptionEdit = new QLineEdit;
1321 m_pShiftAltGrCaptionLabel->setBuddy(m_pShiftAltGrCaptionEdit);
1322 pCaptionEditorLayout->addWidget(m_pShiftAltGrCaptionLabel, 3, 0);
1323 pCaptionEditorLayout->addWidget(m_pShiftAltGrCaptionEdit, 3, 1);
1324 connect(m_pShiftAltGrCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1325
1326 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
1327 if (pSpacer)
1328 pCaptionEditorLayout->addItem(pSpacer, 4, 1);
1329 return m_pCaptionEditGroupBox;
1330}
1331
1332void UIKeyboardLayoutEditor::reset()
1333{
1334 if (m_pLayoutNameEdit)
1335 m_pLayoutNameEdit->clear();
1336 resetKeyWidgets();
1337}
1338
1339void UIKeyboardLayoutEditor::resetKeyWidgets()
1340{
1341 if (m_pScanCodeEdit)
1342 m_pScanCodeEdit->clear();
1343 if (m_pPositionEdit)
1344 m_pPositionEdit->clear();
1345 if (m_pBaseCaptionEdit)
1346 m_pBaseCaptionEdit->clear();
1347 if (m_pShiftCaptionEdit)
1348 m_pShiftCaptionEdit->clear();
1349 if (m_pAltGrCaptionEdit)
1350 m_pAltGrCaptionEdit->clear();
1351 if (m_pShiftAltGrCaptionEdit)
1352 m_pShiftAltGrCaptionEdit->clear();
1353}
1354
1355/*********************************************************************************************************************************
1356* UILayoutSelector implementation. *
1357*********************************************************************************************************************************/
1358
1359UILayoutSelector::UILayoutSelector(QWidget *pParent /* = 0 */)
1360 :QWidget(pParent)
1361 , m_pLayoutListWidget(0)
1362 , m_pApplyLayoutButton(0)
1363 , m_pEditLayoutButton(0)
1364 , m_pCopyLayoutButton(0)
1365 , m_pSaveLayoutButton(0)
1366 , m_pDeleteLayoutButton(0)
1367 , m_pTitleLabel(0)
1368 , m_pCloseButton(0)
1369{
1370 prepareObjects();
1371}
1372
1373void UILayoutSelector::setCurrentLayout(const QUuid &layoutUid)
1374{
1375 if (!m_pLayoutListWidget)
1376 return;
1377 if (layoutUid.isNull())
1378 {
1379 m_pLayoutListWidget->selectionModel()->clear();
1380 return;
1381 }
1382 QListWidgetItem *pFoundItem = 0;
1383 for (int i = 0; i < m_pLayoutListWidget->count() && !pFoundItem; ++i)
1384 {
1385 QListWidgetItem *pItem = m_pLayoutListWidget->item(i);
1386 if (!pItem)
1387 continue;
1388 if (pItem->data(Qt::UserRole).toUuid() == layoutUid)
1389 pFoundItem = pItem;
1390 }
1391 if (!pFoundItem)
1392 return;
1393 if (pFoundItem == m_pLayoutListWidget->currentItem())
1394 return;
1395 m_pLayoutListWidget->blockSignals(true);
1396 m_pLayoutListWidget->setCurrentItem(pFoundItem);
1397 m_pLayoutListWidget->blockSignals(false);
1398}
1399
1400void UILayoutSelector::setCurrentLayoutIsEditable(bool fEditable)
1401{
1402 if (m_pEditLayoutButton)
1403 m_pEditLayoutButton->setEnabled(fEditable);
1404 if (m_pSaveLayoutButton)
1405 m_pSaveLayoutButton->setEnabled(fEditable);
1406 if (m_pDeleteLayoutButton)
1407 m_pDeleteLayoutButton->setEnabled(fEditable);
1408}
1409
1410void UILayoutSelector::setLayoutList(const QStringList &layoutNames, QList<QUuid> layoutUidList)
1411{
1412 if (!m_pLayoutListWidget || layoutNames.size() != layoutUidList.size())
1413 return;
1414 QUuid currentItemUid;
1415 if (m_pLayoutListWidget->currentItem())
1416 currentItemUid = m_pLayoutListWidget->currentItem()->data(Qt::UserRole).toUuid();
1417 m_pLayoutListWidget->blockSignals(true);
1418 m_pLayoutListWidget->clear();
1419 for (int i = 0; i < layoutNames.size(); ++i)
1420 {
1421 QListWidgetItem *pItem = new QListWidgetItem(layoutNames[i], m_pLayoutListWidget);
1422 pItem->setData(Qt::UserRole, layoutUidList[i]);
1423 m_pLayoutListWidget->addItem(pItem);
1424 if (layoutUidList[i] == currentItemUid)
1425 m_pLayoutListWidget->setCurrentItem(pItem);
1426 }
1427 m_pLayoutListWidget->sortItems();
1428 m_pLayoutListWidget->blockSignals(false);
1429}
1430
1431void UILayoutSelector::prepareObjects()
1432{
1433 QVBoxLayout *pLayout = new QVBoxLayout;
1434 if (!pLayout)
1435 return;
1436 pLayout->setSpacing(0);
1437 setLayout(pLayout);
1438
1439 QHBoxLayout *pTitleLayout = new QHBoxLayout;
1440 m_pCloseButton = new QToolButton;
1441 m_pCloseButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
1442 m_pCloseButton->setIcon(UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_DialogCancel));
1443 m_pCloseButton->setAutoRaise(true);
1444 connect(m_pCloseButton, &QToolButton::clicked, this, &UILayoutSelector::sigCloseLayoutList);
1445 m_pTitleLabel = new QLabel;
1446 pTitleLayout->addWidget(m_pTitleLabel);
1447 pTitleLayout->addStretch(2);
1448 pTitleLayout->addWidget(m_pCloseButton);
1449 pLayout->addLayout(pTitleLayout);
1450
1451 m_pLayoutListWidget = new QListWidget;
1452 pLayout->addWidget(m_pLayoutListWidget);
1453 m_pLayoutListWidget->setSortingEnabled(true);
1454 connect(m_pLayoutListWidget, &QListWidget::currentItemChanged, this, &UILayoutSelector::sltCurrentItemChanged);
1455
1456 m_pLayoutListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
1457 QHBoxLayout *pButtonsLayout = new QHBoxLayout;
1458 pLayout->addLayout(pButtonsLayout);
1459
1460 m_pEditLayoutButton = new QToolButton;
1461 m_pEditLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_edit_16px.png", ":/soft_keyboard_layout_edit_disabled_16px.png"));
1462 pButtonsLayout->addWidget(m_pEditLayoutButton);
1463 connect(m_pEditLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigShowLayoutEditor);
1464
1465 m_pCopyLayoutButton = new QToolButton;
1466 m_pCopyLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_copy_16px.png", ":/soft_keyboard_layout_copy_disabled_16px.png"));
1467 pButtonsLayout->addWidget(m_pCopyLayoutButton);
1468 connect(m_pCopyLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigCopyLayout);
1469
1470 m_pSaveLayoutButton = new QToolButton;
1471 m_pSaveLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_save_16px.png", ":/soft_keyboard_layout_save_disabled_16px.png"));
1472 pButtonsLayout->addWidget(m_pSaveLayoutButton);
1473 connect(m_pSaveLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigSaveLayout);
1474
1475 m_pDeleteLayoutButton = new QToolButton;
1476 m_pDeleteLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_remove_16px.png", ":/soft_keyboard_layout_remove_disabled_16px.png"));
1477 pButtonsLayout->addWidget(m_pDeleteLayoutButton);
1478 connect(m_pDeleteLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigDeleteLayout);
1479
1480 pButtonsLayout->addStretch(2);
1481
1482 sltRetranslateUI();
1483 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
1484 this, &UILayoutSelector::sltRetranslateUI);
1485}
1486
1487void UILayoutSelector::sltCurrentItemChanged(QListWidgetItem *pCurrent, QListWidgetItem *pPrevious)
1488{
1489 Q_UNUSED(pPrevious);
1490 if (!pCurrent)
1491 return;
1492 emit sigLayoutSelectionChanged(pCurrent->data(Qt::UserRole).toUuid());
1493}
1494
1495void UILayoutSelector::sltRetranslateUI()
1496{
1497 if (m_pApplyLayoutButton)
1498 m_pApplyLayoutButton->setToolTip(UISoftKeyboard::tr("Use the selected layout"));
1499 if (m_pEditLayoutButton)
1500 m_pEditLayoutButton->setToolTip(UISoftKeyboard::tr("Edit the selected layout"));
1501 if (m_pDeleteLayoutButton)
1502 m_pDeleteLayoutButton->setToolTip(UISoftKeyboard::tr("Delete the selected layout"));
1503 if (m_pCopyLayoutButton)
1504 m_pCopyLayoutButton->setToolTip(UISoftKeyboard::tr("Copy the selected layout"));
1505 if (m_pSaveLayoutButton)
1506 m_pSaveLayoutButton->setToolTip(UISoftKeyboard::tr("Save the selected layout into File"));
1507 if (m_pTitleLabel)
1508 m_pTitleLabel->setText(UISoftKeyboard::tr("Layout List"));
1509 if (m_pCloseButton)
1510 {
1511 m_pCloseButton->setToolTip(UISoftKeyboard::tr("Close the layout list"));
1512 m_pCloseButton->setText(UISoftKeyboard::tr("Close"));
1513 }
1514}
1515
1516
1517/*********************************************************************************************************************************
1518* UISoftKeyboardRow implementation. *
1519*********************************************************************************************************************************/
1520
1521UISoftKeyboardRow::UISoftKeyboardRow()
1522 : m_iDefaultWidth(0)
1523 , m_iDefaultHeight(0)
1524 , m_iSpaceHeightAfter(0)
1525 , m_iLeftMargin(0)
1526{
1527}
1528
1529void UISoftKeyboardRow::setDefaultWidth(int iWidth)
1530{
1531 m_iDefaultWidth = iWidth;
1532}
1533
1534int UISoftKeyboardRow::defaultWidth() const
1535{
1536 return m_iDefaultWidth;
1537}
1538
1539int UISoftKeyboardRow::totalHeight() const
1540{
1541 int iMaxHeight = 0;
1542 for (int i = 0; i < m_keys.size(); ++i)
1543 iMaxHeight = qMax(iMaxHeight, m_keys[i].height());
1544 return iMaxHeight + m_iSpaceHeightAfter;
1545}
1546
1547void UISoftKeyboardRow::setDefaultHeight(int iHeight)
1548{
1549 m_iDefaultHeight = iHeight;
1550}
1551
1552int UISoftKeyboardRow::defaultHeight() const
1553{
1554 return m_iDefaultHeight;
1555}
1556
1557QVector<UISoftKeyboardKey> &UISoftKeyboardRow::keys()
1558{
1559 return m_keys;
1560}
1561
1562const QVector<UISoftKeyboardKey> &UISoftKeyboardRow::keys() const
1563{
1564 return m_keys;
1565}
1566
1567void UISoftKeyboardRow::setSpaceHeightAfter(int iSpace)
1568{
1569 m_iSpaceHeightAfter = iSpace;
1570}
1571
1572int UISoftKeyboardRow::spaceHeightAfter() const
1573{
1574 return m_iSpaceHeightAfter;
1575}
1576
1577int UISoftKeyboardRow::leftMargin() const
1578{
1579 return m_iLeftMargin;
1580}
1581
1582void UISoftKeyboardRow::setLeftMargin(int iMargin)
1583{
1584 m_iLeftMargin = iMargin;
1585}
1586
1587/*********************************************************************************************************************************
1588* UISoftKeyboardKey implementation. *
1589*********************************************************************************************************************************/
1590
1591UISoftKeyboardKey::UISoftKeyboardKey()
1592 : m_enmType(KeyType_Ordinary)
1593 , m_enmState(KeyState_NotPressed)
1594 , m_iWidth(0)
1595 , m_iHeight(0)
1596 , m_iSpaceWidthAfter(0)
1597 , m_scanCode(0)
1598 , m_iCutoutWidth(0)
1599 , m_iCutoutHeight(0)
1600 , m_iCutoutCorner(-1)
1601 , m_iPosition(0)
1602 , m_pParentWidget(0)
1603 , m_iUsageId(0)
1604 , m_iUsagePage(0)
1605 , m_enmKeyboardRegion(KeyboardRegion_Main)
1606 , m_fIsOSMenuKey(false)
1607 , m_fCornerRadius(5.)
1608{
1609}
1610
1611const QRect UISoftKeyboardKey::keyGeometry() const
1612{
1613 return m_keyGeometry;
1614}
1615
1616void UISoftKeyboardKey::setKeyGeometry(const QRect &rect)
1617{
1618 m_keyGeometry = rect;
1619}
1620
1621
1622void UISoftKeyboardKey::setWidth(int iWidth)
1623{
1624 m_iWidth = iWidth;
1625}
1626
1627int UISoftKeyboardKey::width() const
1628{
1629 return m_iWidth;
1630}
1631
1632void UISoftKeyboardKey::setHeight(int iHeight)
1633{
1634 m_iHeight = iHeight;
1635}
1636
1637int UISoftKeyboardKey::height() const
1638{
1639 return m_iHeight;
1640}
1641
1642void UISoftKeyboardKey::setScanCode(LONG scanCode)
1643{
1644 m_scanCode = scanCode;
1645}
1646
1647LONG UISoftKeyboardKey::scanCode() const
1648{
1649 return m_scanCode;
1650}
1651
1652void UISoftKeyboardKey::addScanCodePrefix(LONG scanCodePrefix)
1653{
1654 m_scanCodePrefix << scanCodePrefix;
1655}
1656
1657void UISoftKeyboardKey::setSpaceWidthAfter(int iSpace)
1658{
1659 m_iSpaceWidthAfter = iSpace;
1660}
1661
1662int UISoftKeyboardKey::spaceWidthAfter() const
1663{
1664 return m_iSpaceWidthAfter;
1665}
1666
1667void UISoftKeyboardKey::setUsageId(LONG usageId)
1668{
1669 m_iUsageId = usageId;
1670}
1671
1672void UISoftKeyboardKey::setUsagePage(LONG usagePage)
1673{
1674 m_iUsagePage = usagePage;
1675}
1676
1677QPair<LONG, LONG> UISoftKeyboardKey::usagePageIdPair() const
1678{
1679 return QPair<LONG, LONG>(m_iUsageId, m_iUsagePage);
1680}
1681
1682void UISoftKeyboardKey::setPosition(int iPosition)
1683{
1684 m_iPosition = iPosition;
1685}
1686
1687int UISoftKeyboardKey::position() const
1688{
1689 return m_iPosition;
1690}
1691
1692void UISoftKeyboardKey::setType(KeyType enmType)
1693{
1694 m_enmType = enmType;
1695}
1696
1697KeyType UISoftKeyboardKey::type() const
1698{
1699 return m_enmType;
1700}
1701
1702KeyboardRegion UISoftKeyboardKey::keyboardRegion() const
1703{
1704 return m_enmKeyboardRegion;
1705}
1706
1707void UISoftKeyboardKey::setKeyboardRegion(KeyboardRegion enmRegion)
1708{
1709 m_enmKeyboardRegion = enmRegion;
1710}
1711
1712void UISoftKeyboardKey::setCutout(int iCorner, int iWidth, int iHeight)
1713{
1714 m_iCutoutCorner = iCorner;
1715 m_iCutoutWidth = iWidth;
1716 m_iCutoutHeight = iHeight;
1717}
1718
1719KeyState UISoftKeyboardKey::state() const
1720{
1721 return m_enmState;
1722}
1723
1724void UISoftKeyboardKey::setState(KeyState state)
1725{
1726 m_enmState = state;
1727}
1728
1729void UISoftKeyboardKey::setStaticCaption(const QString &strCaption)
1730{
1731 m_strStaticCaption = strCaption;
1732}
1733
1734const QString &UISoftKeyboardKey::staticCaption() const
1735{
1736 return m_strStaticCaption;
1737}
1738
1739void UISoftKeyboardKey::setImageByName(const QString &strImageFileName)
1740{
1741 if (strImageFileName.isEmpty())
1742 return;
1743 m_icon = UIIconPool::iconSet(QString(":/%1").arg(strImageFileName));
1744}
1745
1746QPixmap UISoftKeyboardKey::image() const
1747{
1748 QPixmap pixmap;
1749
1750 /* Check whether we have valid icon: */
1751 if (!m_icon.isNull())
1752 {
1753 /* Determine desired icon size: */
1754 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize);
1755 const QSize iconSize = QSize(iIconMetric, iIconMetric);
1756 /* Get pixmap of requested size (take into account the DPI of the main shown window, if possible): */
1757 const qreal fDevicePixelRatio = windowManager().mainWindowShown() && windowManager().mainWindowShown()->windowHandle()
1758 ? windowManager().mainWindowShown()->windowHandle()->devicePixelRatio() : 1;
1759 pixmap = m_icon.pixmap(iconSize, fDevicePixelRatio);
1760 }
1761
1762 return pixmap;
1763}
1764
1765void UISoftKeyboardKey::setParentWidget(UISoftKeyboardWidget* pParent)
1766{
1767 m_pParentWidget = pParent;
1768}
1769
1770void UISoftKeyboardKey::setIsOSMenuKey(bool fFlag)
1771{
1772 m_fIsOSMenuKey = fFlag;
1773}
1774
1775bool UISoftKeyboardKey::isOSMenuKey() const
1776{
1777 return m_fIsOSMenuKey;
1778}
1779
1780void UISoftKeyboardKey::release()
1781{
1782 /* Lock key states are controlled by the event signals we get from the guest OS. See updateLockKeyState function: */
1783 if (m_enmType != KeyType_Lock)
1784 updateState(false);
1785}
1786
1787void UISoftKeyboardKey::press()
1788{
1789 /* Lock key states are controlled by the event signals we get from the guest OS. See updateLockKeyState function: */
1790 if (m_enmType != KeyType_Lock)
1791 updateState(true);
1792}
1793
1794void UISoftKeyboardKey::setPoints(const QVector<QPointF> &points)
1795{
1796 m_points = points;
1797 computePainterPath();
1798}
1799
1800const QVector<QPointF> &UISoftKeyboardKey::points() const
1801{
1802 return m_points;
1803}
1804
1805const QPainterPath &UISoftKeyboardKey::painterPath() const
1806{
1807 return m_painterPath;
1808}
1809
1810void UISoftKeyboardKey::computePainterPath()
1811{
1812 if (m_points.size() < 3)
1813 return;
1814
1815 m_painterPath = QPainterPath(pointInBetween(m_fCornerRadius, m_points[0], m_points[1]));
1816 for (int i = 0; i < m_points.size(); ++i)
1817 {
1818 QPointF p0 = pointInBetween(m_fCornerRadius, m_points[(i+1)%m_points.size()], m_points[i]);
1819 QPointF p1 = pointInBetween(m_fCornerRadius, m_points[(i+1)%m_points.size()], m_points[(i+2)%m_points.size()]);
1820 m_painterPath.lineTo(p0);
1821 m_painterPath.quadTo(m_points[(i+1)%m_points.size()], p1);
1822 }
1823}
1824
1825void UISoftKeyboardKey::setCornerRadius(float fCornerRadius)
1826{
1827 m_fCornerRadius = fCornerRadius;
1828}
1829
1830QPolygonF UISoftKeyboardKey::polygonInGlobal() const
1831{
1832 QPolygonF globalPolygon(m_points);
1833 globalPolygon.translate(m_keyGeometry.x(), m_keyGeometry.y());
1834 return globalPolygon;
1835}
1836
1837int UISoftKeyboardKey::cutoutCorner() const
1838{
1839 return m_iCutoutCorner;
1840}
1841
1842int UISoftKeyboardKey::cutoutWidth() const
1843{
1844 return m_iCutoutWidth;
1845}
1846
1847int UISoftKeyboardKey::cutoutHeight() const
1848{
1849 return m_iCutoutHeight;
1850}
1851
1852void UISoftKeyboardKey::updateState(bool fPressed)
1853{
1854 KeyState enmPreviousState = state();
1855 if (m_enmType == KeyType_Modifier)
1856 {
1857 if (fPressed)
1858 {
1859 if (m_enmState == KeyState_NotPressed)
1860 m_enmState = KeyState_Pressed;
1861 else if(m_enmState == KeyState_Pressed)
1862 m_enmState = KeyState_Locked;
1863 else
1864 m_enmState = KeyState_NotPressed;
1865 }
1866 else
1867 {
1868 if(m_enmState == KeyState_Pressed)
1869 m_enmState = KeyState_NotPressed;
1870 }
1871 }
1872 else if (m_enmType == KeyType_Lock)
1873 {
1874 m_enmState = fPressed ? KeyState_Locked : KeyState_NotPressed;
1875 }
1876 else if (m_enmType == KeyType_Ordinary)
1877 {
1878 if (m_enmState == KeyState_NotPressed)
1879 m_enmState = KeyState_Pressed;
1880 else
1881 m_enmState = KeyState_NotPressed;
1882 }
1883 if (enmPreviousState != state() && m_pParentWidget)
1884 m_pParentWidget->keyStateChange(this);
1885}
1886
1887void UISoftKeyboardKey::updateLockState(bool fLocked)
1888{
1889 if (m_enmType != KeyType_Lock)
1890 return;
1891 if (fLocked && m_enmState == KeyState_Locked)
1892 return;
1893 if (!fLocked && m_enmState == KeyState_NotPressed)
1894 return;
1895 updateState(fLocked);
1896}
1897
1898void UISoftKeyboardKey::reset()
1899{
1900 m_enmState = KeyState_NotPressed;
1901}
1902
1903
1904/*********************************************************************************************************************************
1905* UISoftKeyboardLayout implementation. *
1906*********************************************************************************************************************************/
1907
1908UISoftKeyboardLayout::UISoftKeyboardLayout()
1909 : m_fEditable(true)
1910 , m_fIsFromResources(false)
1911 , m_fEditedButNotSaved(false)
1912 , m_uid(QUuid::createUuid())
1913{
1914}
1915
1916QString UISoftKeyboardLayout::nameString() const
1917{
1918 QString strCombinedName;
1919 if (nativeName().isEmpty() && !name().isEmpty())
1920 strCombinedName = name();
1921 else if (!nativeName().isEmpty() && name().isEmpty())
1922 strCombinedName = nativeName();
1923 else
1924 strCombinedName = QString("%1 (%2)").arg(nativeName()).arg(name());
1925 return strCombinedName;
1926}
1927
1928void UISoftKeyboardLayout::setSourceFilePath(const QString& strSourceFilePath)
1929{
1930 m_strSourceFilePath = strSourceFilePath;
1931 setEditedBuNotSaved(true);
1932}
1933
1934const QString& UISoftKeyboardLayout::sourceFilePath() const
1935{
1936 return m_strSourceFilePath;
1937}
1938
1939void UISoftKeyboardLayout::setIsFromResources(bool fIsFromResources)
1940{
1941 m_fIsFromResources = fIsFromResources;
1942 setEditedBuNotSaved(true);
1943}
1944
1945bool UISoftKeyboardLayout::isFromResources() const
1946{
1947 return m_fIsFromResources;
1948}
1949
1950void UISoftKeyboardLayout::setName(const QString &strName)
1951{
1952 m_strName = strName;
1953 setEditedBuNotSaved(true);
1954}
1955
1956const QString &UISoftKeyboardLayout::name() const
1957{
1958 return m_strName;
1959}
1960
1961void UISoftKeyboardLayout::setNativeName(const QString &strNativeName)
1962{
1963 m_strNativeName = strNativeName;
1964 setEditedBuNotSaved(true);
1965}
1966
1967const QString &UISoftKeyboardLayout::nativeName() const
1968{
1969 return m_strNativeName;
1970}
1971
1972void UISoftKeyboardLayout::setEditable(bool fEditable)
1973{
1974 m_fEditable = fEditable;
1975 setEditedBuNotSaved(true);
1976}
1977
1978bool UISoftKeyboardLayout::editable() const
1979{
1980 return m_fEditable;
1981}
1982
1983void UISoftKeyboardLayout::setPhysicalLayoutUuid(const QUuid &uuid)
1984{
1985 m_physicalLayoutUuid = uuid;
1986 setEditedBuNotSaved(true);
1987}
1988
1989const QUuid &UISoftKeyboardLayout::physicalLayoutUuid() const
1990{
1991 return m_physicalLayoutUuid;
1992}
1993
1994void UISoftKeyboardLayout::addOrUpdateUIKeyCaptions(int iKeyPosition, const UIKeyCaptions &keyCaptions)
1995{
1996 if (m_keyCaptionsMap[iKeyPosition] == keyCaptions)
1997 return;
1998 m_keyCaptionsMap[iKeyPosition] = keyCaptions;
1999 /* Updating the captions invalidates the cached font size. We set it to 0, thereby forcing its recomputaion: */
2000 m_keyCaptionsFontSizeMap[iKeyPosition] = 0;
2001 setEditedBuNotSaved(true);
2002}
2003
2004UIKeyCaptions UISoftKeyboardLayout::keyCaptions(int iKeyPosition) const
2005{
2006 return m_keyCaptionsMap[iKeyPosition];
2007}
2008
2009bool UISoftKeyboardLayout::operator==(const UISoftKeyboardLayout &otherLayout) const
2010{
2011 if (m_strName != otherLayout.m_strName)
2012 return false;
2013 if (m_strNativeName != otherLayout.m_strNativeName)
2014 return false;
2015 if (m_physicalLayoutUuid != otherLayout.m_physicalLayoutUuid)
2016 return false;
2017 if (m_fEditable != otherLayout.m_fEditable)
2018 return false;
2019 if (m_strSourceFilePath != otherLayout.m_strSourceFilePath)
2020 return false;
2021 if (m_fIsFromResources != otherLayout.m_fIsFromResources)
2022 return false;
2023 return true;
2024}
2025
2026QString UISoftKeyboardLayout::baseCaption(int iKeyPosition) const
2027{
2028 return m_keyCaptionsMap.value(iKeyPosition, UIKeyCaptions()).m_strBase;
2029}
2030
2031QString UISoftKeyboardLayout::shiftCaption(int iKeyPosition) const
2032{
2033 if (!m_keyCaptionsMap.contains(iKeyPosition))
2034 return QString();
2035 return m_keyCaptionsMap[iKeyPosition].m_strShift;
2036}
2037
2038QString UISoftKeyboardLayout::altGrCaption(int iKeyPosition) const
2039{
2040 if (!m_keyCaptionsMap.contains(iKeyPosition))
2041 return QString();
2042 return m_keyCaptionsMap[iKeyPosition].m_strAltGr;
2043}
2044
2045QString UISoftKeyboardLayout::shiftAltGrCaption(int iKeyPosition) const
2046{
2047 if (!m_keyCaptionsMap.contains(iKeyPosition))
2048 return QString();
2049 return m_keyCaptionsMap[iKeyPosition].m_strShiftAltGr;
2050}
2051
2052void UISoftKeyboardLayout::setEditedBuNotSaved(bool fEditedButNotsaved)
2053{
2054 m_fEditedButNotSaved = fEditedButNotsaved;
2055}
2056
2057bool UISoftKeyboardLayout::editedButNotSaved() const
2058{
2059 return m_fEditedButNotSaved;
2060}
2061
2062void UISoftKeyboardLayout::setUid(const QUuid &uid)
2063{
2064 m_uid = uid;
2065 setEditedBuNotSaved(true);
2066}
2067
2068QUuid UISoftKeyboardLayout::uid() const
2069{
2070 return m_uid;
2071}
2072
2073void UISoftKeyboardLayout::drawTextInRect(const UISoftKeyboardKey &key, QPainter &painter)
2074{
2075 int iKeyPosition = key.position();
2076 const QRect &keyGeometry = key.keyGeometry();
2077 QFont painterFont(painter.font());
2078
2079 QString strBaseCaption;
2080 QString strShiftCaption;
2081 QString strShiftAltGrCaption;
2082 QString strAltGrCaption;
2083
2084 /* Static captions which are defined in the physical layout files have precedence over
2085 the one define in the keyboard layouts. In effect they stay the same for all the
2086 keyboard layouts sharing the same physical layout: */
2087
2088 if (key.staticCaption().isEmpty())
2089 {
2090 strBaseCaption = baseCaption(iKeyPosition);
2091 strShiftCaption = shiftCaption(iKeyPosition);
2092 strShiftAltGrCaption = shiftAltGrCaption(iKeyPosition);
2093 strAltGrCaption = altGrCaption(iKeyPosition);
2094 }
2095 else
2096 strBaseCaption = key.staticCaption();
2097
2098 const QString &strTopleftString = !strShiftCaption.isEmpty() ? strShiftCaption : strBaseCaption;
2099 const QString &strBottomleftString = !strShiftCaption.isEmpty() ? strBaseCaption : QString();
2100
2101 int iFontSize = 30;
2102 if (!m_keyCaptionsFontSizeMap.contains(iKeyPosition) || m_keyCaptionsFontSizeMap.value(iKeyPosition) == 0)
2103 {
2104 do
2105 {
2106 painterFont.setPixelSize(iFontSize);
2107 painterFont.setBold(true);
2108 painter.setFont(painterFont);
2109 const QFontMetrics fontMetrics = painter.fontMetrics();
2110 const int iMargin = 0.25 * fontMetrics.horizontalAdvance('X');
2111
2112 int iTopWidth = 0;
2113 /* Some captions are multi line using \n as separator: */
2114 QStringList strList;
2115 strList << strTopleftString.split("\n", Qt::SkipEmptyParts)
2116 << strShiftAltGrCaption.split("\n", Qt::SkipEmptyParts);
2117 foreach (const QString &strPart, strList)
2118 iTopWidth = qMax(iTopWidth, fontMetrics.horizontalAdvance(strPart));
2119 strList.clear();
2120 strList << strBottomleftString.split("\n", Qt::SkipEmptyParts)
2121 << strAltGrCaption.split("\n", Qt::SkipEmptyParts);
2122
2123 int iBottomWidth = 0;
2124 foreach (const QString &strPart, strList)
2125 iBottomWidth = qMax(iBottomWidth, fontMetrics.horizontalAdvance(strPart));
2126 int iTextWidth = 2 * iMargin + qMax(iTopWidth, iBottomWidth);
2127 int iTextHeight = 0;
2128
2129 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2130 iTextHeight = 2 * iMargin + fontMetrics.height();
2131 else
2132 iTextHeight = 2 * iMargin + 2 * fontMetrics.height();
2133
2134 if (iTextWidth >= keyGeometry.width() || iTextHeight >= keyGeometry.height())
2135 --iFontSize;
2136 else
2137 break;
2138
2139 }while(iFontSize > 1);
2140 m_keyCaptionsFontSizeMap[iKeyPosition] = iFontSize;
2141 }
2142 else
2143 {
2144 iFontSize = m_keyCaptionsFontSizeMap[iKeyPosition];
2145 painterFont.setPixelSize(iFontSize);
2146 painterFont.setBold(true);
2147 painter.setFont(painterFont);
2148 }
2149
2150 const QFontMetrics fontMetrics = painter.fontMetrics();
2151 const int iMargin = 0.25 * fontMetrics.horizontalAdvance('X');
2152 QRect textRect;
2153 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2154 textRect = QRect(2 * iMargin, iMargin,
2155 keyGeometry.width() - 2 * iMargin,
2156 keyGeometry.height() - 2 * iMargin);
2157 else
2158 textRect = QRect(iMargin, iMargin,
2159 keyGeometry.width() - 2 * iMargin,
2160 keyGeometry.height() - 2 * iMargin);
2161
2162 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2163 {
2164 painter.drawText(QRect(0, 0, keyGeometry.width(), keyGeometry.height()),
2165 Qt::AlignHCenter | Qt::AlignVCenter, strTopleftString);
2166 }
2167 else
2168 {
2169 painter.drawText(textRect, Qt::AlignLeft | Qt::AlignTop, strTopleftString);
2170 painter.drawText(textRect, Qt::AlignLeft | Qt::AlignBottom, strBottomleftString);
2171 painter.drawText(textRect, Qt::AlignRight | Qt::AlignTop, strShiftAltGrCaption);
2172 painter.drawText(textRect, Qt::AlignRight | Qt::AlignBottom, strAltGrCaption);
2173 }
2174}
2175
2176void UISoftKeyboardLayout::drawKeyImageInRect(const UISoftKeyboardKey &key, QPainter &painter)
2177{
2178 if (key.image().isNull())
2179 return;
2180 const QRect &keyGeometry = key.keyGeometry();
2181 int iMargin = 0.1 * qMax(keyGeometry.width(), keyGeometry.height());
2182 int size = qMin(keyGeometry.width() - 2 * iMargin, keyGeometry.height() - 2 * iMargin);
2183 painter.drawPixmap(QRect(0.5 * (keyGeometry.width() - size), 0.5 * (keyGeometry.height() - size),
2184 size, size), key.image());
2185}
2186
2187
2188/*********************************************************************************************************************************
2189* UISoftKeyboardColorTheme implementation. *
2190*********************************************************************************************************************************/
2191
2192UISoftKeyboardColorTheme::UISoftKeyboardColorTheme()
2193 : m_colors(QVector<QColor>(KeyboardColorType_Max))
2194 , m_fIsEditable(false)
2195{
2196 m_colors[KeyboardColorType_Background].setNamedColor("#ff878787");
2197 m_colors[KeyboardColorType_Font].setNamedColor("#ff000000");
2198 m_colors[KeyboardColorType_Hover].setNamedColor("#ff676767");
2199 m_colors[KeyboardColorType_Edit].setNamedColor("#ff9b6767");
2200 m_colors[KeyboardColorType_Pressed].setNamedColor("#fffafafa");
2201}
2202
2203UISoftKeyboardColorTheme::UISoftKeyboardColorTheme(const QString &strName,
2204 const QString &strBackgroundColor,
2205 const QString &strNormalFontColor,
2206 const QString &strHoverColor,
2207 const QString &strEditedButtonBackgroundColor,
2208 const QString &strPressedButtonFontColor)
2209 :m_colors(QVector<QColor>(KeyboardColorType_Max))
2210 ,m_strName(strName)
2211 , m_fIsEditable(false)
2212{
2213 m_colors[KeyboardColorType_Background].setNamedColor(strBackgroundColor);
2214 m_colors[KeyboardColorType_Font].setNamedColor(strNormalFontColor);
2215 m_colors[KeyboardColorType_Hover].setNamedColor(strHoverColor);
2216 m_colors[KeyboardColorType_Edit].setNamedColor(strEditedButtonBackgroundColor);
2217 m_colors[KeyboardColorType_Pressed].setNamedColor(strPressedButtonFontColor);
2218}
2219
2220
2221void UISoftKeyboardColorTheme::setColor(KeyboardColorType enmColorType, const QColor &color)
2222{
2223 if ((int) enmColorType >= m_colors.size())
2224 return;
2225 m_colors[(int)enmColorType] = color;
2226}
2227
2228QColor UISoftKeyboardColorTheme::color(KeyboardColorType enmColorType) const
2229{
2230 if ((int) enmColorType >= m_colors.size())
2231 return QColor();
2232 return m_colors[(int)enmColorType];
2233}
2234
2235QStringList UISoftKeyboardColorTheme::colorsToStringList() const
2236{
2237 QStringList colorStringList;
2238 foreach (const QColor &color, m_colors)
2239 colorStringList << color.name(QColor::HexArgb);
2240 return colorStringList;
2241}
2242
2243void UISoftKeyboardColorTheme::colorsFromStringList(const QStringList &colorStringList)
2244{
2245 for (int i = 0; i < colorStringList.size() && i < m_colors.size(); ++i)
2246 {
2247 if (!QColor::isValidColor(colorStringList[i]))
2248 continue;
2249 m_colors[i].setNamedColor(colorStringList[i]);
2250 }
2251}
2252
2253const QString &UISoftKeyboardColorTheme::name() const
2254{
2255 return m_strName;
2256}
2257
2258void UISoftKeyboardColorTheme::setName(const QString &strName)
2259{
2260 m_strName = strName;
2261}
2262
2263bool UISoftKeyboardColorTheme::isEditable() const
2264{
2265 return m_fIsEditable;
2266}
2267
2268void UISoftKeyboardColorTheme::setIsEditable(bool fIsEditable)
2269{
2270 m_fIsEditable = fIsEditable;
2271}
2272
2273/*********************************************************************************************************************************
2274* UISoftKeyboardWidget implementation. *
2275*********************************************************************************************************************************/
2276
2277UISoftKeyboardWidget::UISoftKeyboardWidget(QWidget *pParent, UIMachine *pMachine)
2278 : QWidget(pParent)
2279 , m_pMachine(pMachine)
2280 , m_pKeyUnderMouse(0)
2281 , m_pKeyBeingEdited(0)
2282 , m_pKeyPressed(0)
2283 , m_currentColorTheme(0)
2284 , m_iInitialHeight(0)
2285 , m_iInitialWidth(0)
2286 , m_iInitialWidthNoNumPad(0)
2287 , m_iBeforeNumPadWidth(30)
2288 , m_iXSpacing(5)
2289 , m_iYSpacing(5)
2290 , m_iLeftMargin(10)
2291 , m_iTopMargin(10)
2292 , m_iRightMargin(10)
2293 , m_iBottomMargin(10)
2294 , m_enmMode(Mode_Keyboard)
2295 , m_fHideOSMenuKeys(false)
2296 , m_fHideNumPad(false)
2297 , m_fHideMultimediaKeys(false)
2298{
2299 prepareObjects();
2300 prepareColorThemes();
2301 sltRetranslateUI();
2302
2303 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
2304 this, &UISoftKeyboardWidget::sltRetranslateUI);
2305}
2306
2307QSize UISoftKeyboardWidget::minimumSizeHint() const
2308{
2309 float fScale = 0.5f;
2310 return QSize(fScale * m_minimumSize.width(), fScale * m_minimumSize.height());
2311}
2312
2313QSize UISoftKeyboardWidget::sizeHint() const
2314{
2315 float fScale = 0.5f;
2316 return QSize(fScale * m_minimumSize.width(), fScale * m_minimumSize.height());
2317}
2318
2319void UISoftKeyboardWidget::paintEvent(QPaintEvent *pEvent) /* RT_OVERRIDE */
2320{
2321 Q_UNUSED(pEvent);
2322 if (!m_layouts.contains(m_uCurrentLayoutId))
2323 return;
2324
2325 UISoftKeyboardLayout &currentLayout = m_layouts[m_uCurrentLayoutId];
2326
2327 if (m_iInitialWidth == 0 || m_iInitialWidthNoNumPad == 0 || m_iInitialHeight == 0)
2328 return;
2329
2330 if (!m_fHideNumPad)
2331 m_fScaleFactorX = width() / (float) (m_iInitialWidth + m_iBeforeNumPadWidth);
2332 else
2333 m_fScaleFactorX = width() / (float) m_iInitialWidthNoNumPad;
2334
2335 if (!m_fHideMultimediaKeys)
2336 m_fScaleFactorY = height() / (float) m_iInitialHeight;
2337 else
2338 m_fScaleFactorY = height() / (float)(m_iInitialHeight - m_multiMediaKeysLayout.totalHeight());
2339
2340 QPainter painter(this);
2341 QFont painterFont(font());
2342 painterFont.setPixelSize(15);
2343 painterFont.setBold(true);
2344 painter.setFont(painterFont);
2345 painter.setRenderHint(QPainter::Antialiasing);
2346 painter.setRenderHint(QPainter::SmoothPixmapTransform);
2347 painter.scale(m_fScaleFactorX, m_fScaleFactorY);
2348 int unitSize = qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
2349 float fLedRadius = 0.8 * unitSize;
2350 float fLedMargin = 5;//0.6 * unitSize;
2351
2352 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(currentLayout.physicalLayoutUuid());
2353 if (!pPhysicalLayout)
2354 return;
2355
2356 QVector<UISoftKeyboardRow> &rows = pPhysicalLayout->rows();
2357 for (int i = 0; i < rows.size(); ++i)
2358 {
2359 QVector<UISoftKeyboardKey> &keys = rows[i].keys();
2360 for (int j = 0; j < keys.size(); ++j)
2361 {
2362 UISoftKeyboardKey &key = keys[j];
2363
2364 if (m_fHideOSMenuKeys && key.isOSMenuKey())
2365 continue;
2366
2367 if (m_fHideNumPad && key.keyboardRegion() == KeyboardRegion_NumPad)
2368 continue;
2369
2370 if (m_fHideMultimediaKeys && key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2371 continue;
2372
2373 if (m_fHideMultimediaKeys)
2374 painter.translate(key.keyGeometry().x(), key.keyGeometry().y() - m_multiMediaKeysLayout.totalHeight());
2375 else
2376 painter.translate(key.keyGeometry().x(), key.keyGeometry().y());
2377
2378 if(&key == m_pKeyBeingEdited)
2379 painter.setBrush(QBrush(color(KeyboardColorType_Edit)));
2380 else if (&key == m_pKeyUnderMouse)
2381 painter.setBrush(QBrush(color(KeyboardColorType_Hover)));
2382 else
2383 painter.setBrush(QBrush(color(KeyboardColorType_Background)));
2384
2385 if (&key == m_pKeyPressed)
2386 painter.setPen(QPen(color(KeyboardColorType_Pressed), 2));
2387 else
2388 painter.setPen(QPen(color(KeyboardColorType_Font), 2));
2389
2390 /* Draw the key shape: */
2391 painter.drawPath(key.painterPath());
2392
2393 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2394 currentLayout.drawKeyImageInRect(key, painter);
2395 else
2396 currentLayout.drawTextInRect(key, painter);
2397 /* Draw small LED like circles on the modifier/lock keys: */
2398 if (key.type() != KeyType_Ordinary)
2399 {
2400 QColor ledColor;
2401 if (key.type() == KeyType_Lock)
2402 {
2403 if (key.state() == KeyState_NotPressed)
2404 ledColor = color(KeyboardColorType_Font);
2405 else
2406 ledColor = QColor(0, 255, 0);
2407 }
2408 else
2409 {
2410 if (key.state() == KeyState_NotPressed)
2411 ledColor = color(KeyboardColorType_Font);
2412 else if (key.state() == KeyState_Pressed)
2413 ledColor = QColor(0, 191, 204);
2414 else
2415 ledColor = QColor(255, 50, 50);
2416 }
2417 if (m_enmMode == Mode_LayoutEdit)
2418 ledColor = color(KeyboardColorType_Font);
2419 painter.setBrush(ledColor);
2420 painter.setPen(ledColor);
2421 QRectF rectangle(key.keyGeometry().width() - 2 * fLedMargin, key.keyGeometry().height() - 2 * fLedMargin,
2422 fLedRadius, fLedRadius);
2423 painter.drawEllipse(rectangle);
2424 }
2425 if (m_fHideMultimediaKeys)
2426 painter.translate(-key.keyGeometry().x(), -key.keyGeometry().y() + m_multiMediaKeysLayout.totalHeight());
2427 else
2428 painter.translate(-key.keyGeometry().x(), -key.keyGeometry().y());
2429 }
2430 }
2431}
2432
2433void UISoftKeyboardWidget::mousePressEvent(QMouseEvent *pEvent)
2434{
2435 QWidget::mousePressEvent(pEvent);
2436 if (pEvent->button() != Qt::RightButton && pEvent->button() != Qt::LeftButton)
2437 return;
2438
2439 m_pKeyPressed = keyUnderMouse(pEvent);
2440 if (!m_pKeyPressed)
2441 return;
2442
2443 /* Handling the right button press: */
2444 if (pEvent->button() == Qt::RightButton)
2445 modifierKeyPressRelease(m_pKeyPressed, false);
2446 else
2447 {
2448 /* Handling the left button press: */
2449 if (m_enmMode == Mode_Keyboard)
2450 handleKeyPress(m_pKeyPressed);
2451 else if (m_enmMode == Mode_LayoutEdit)
2452 setKeyBeingEdited(m_pKeyUnderMouse);
2453 }
2454 update();
2455}
2456
2457void UISoftKeyboardWidget::mouseReleaseEvent(QMouseEvent *pEvent)
2458{
2459 QWidget::mouseReleaseEvent(pEvent);
2460
2461 if (pEvent->button() != Qt::RightButton && pEvent->button() != Qt::LeftButton)
2462 return;
2463
2464 if (!m_pKeyPressed)
2465 return;
2466 if (pEvent->button() == Qt::RightButton)
2467 modifierKeyPressRelease(m_pKeyPressed, true);
2468 else
2469 {
2470 if (m_enmMode == Mode_Keyboard)
2471 handleKeyRelease(m_pKeyPressed);
2472 }
2473 m_pKeyPressed = 0;
2474 update();
2475}
2476
2477void UISoftKeyboardWidget::mouseMoveEvent(QMouseEvent *pEvent)
2478{
2479 QWidget::mouseMoveEvent(pEvent);
2480 UISoftKeyboardKey *pPreviousKeyUnderMouse = m_pKeyUnderMouse;
2481 keyUnderMouse(pEvent);
2482 if (pPreviousKeyUnderMouse != m_pKeyUnderMouse)
2483 showKeyTooltip(m_pKeyUnderMouse);
2484}
2485
2486void UISoftKeyboardWidget::sltRetranslateUI()
2487{
2488 m_keyTooltips[317] = UISoftKeyboard::tr("Power off");
2489 m_keyTooltips[300] = UISoftKeyboard::tr("Web browser go back");
2490 m_keyTooltips[301] = UISoftKeyboard::tr("Web browser go the home page");
2491 m_keyTooltips[302] = UISoftKeyboard::tr("Web browser go forward");
2492 m_keyTooltips[315] = UISoftKeyboard::tr("Web browser reload the current page");
2493 m_keyTooltips[314] = UISoftKeyboard::tr("Web browser stop loading the page");
2494 m_keyTooltips[313] = UISoftKeyboard::tr("Web browser search");
2495
2496 m_keyTooltips[307] = UISoftKeyboard::tr("Jump back to previous media track");
2497 m_keyTooltips[308] = UISoftKeyboard::tr("Jump to next media track");
2498 m_keyTooltips[309] = UISoftKeyboard::tr("Stop playing");
2499 m_keyTooltips[310] = UISoftKeyboard::tr("Play or pause playing");
2500
2501 m_keyTooltips[303] = UISoftKeyboard::tr("Start email application");
2502 m_keyTooltips[311] = UISoftKeyboard::tr("Start calculator");
2503 m_keyTooltips[312] = UISoftKeyboard::tr("Show 'My Computer'");
2504 m_keyTooltips[316] = UISoftKeyboard::tr("Show Media folder");
2505
2506 m_keyTooltips[304] = UISoftKeyboard::tr("Mute");
2507 m_keyTooltips[305] = UISoftKeyboard::tr("Volume down");
2508 m_keyTooltips[306] = UISoftKeyboard::tr("Volume up");
2509}
2510
2511void UISoftKeyboardWidget::saveCurentLayoutToFile()
2512{
2513 if (!m_layouts.contains(m_uCurrentLayoutId))
2514 return;
2515 UISoftKeyboardLayout &currentLayout = m_layouts[m_uCurrentLayoutId];
2516 QString strHomeFolder = gpGlobalSession->homeFolder();
2517 QDir dir(strHomeFolder);
2518 if (!dir.exists(strSubDirectorName))
2519 {
2520 if (!dir.mkdir(strSubDirectorName))
2521 {
2522 sigStatusBarMessage(QString("%1 %2").arg(UISoftKeyboard::tr("Error! Could not create folder under").arg(strHomeFolder)));
2523 return;
2524 }
2525 }
2526
2527 strHomeFolder += QString(QDir::separator()) + strSubDirectorName;
2528 QInputDialog dialog(this);
2529 dialog.setInputMode(QInputDialog::TextInput);
2530 dialog.setWindowModality(Qt::WindowModal);
2531 dialog.setWindowTitle(UISoftKeyboard::tr("Provide a file name"));
2532 dialog.setTextValue(currentLayout.name());
2533 dialog.setLabelText(QString("%1 %2").arg(UISoftKeyboard::tr("The file will be saved under:<br>")).arg(strHomeFolder));
2534 if (dialog.exec() == QDialog::Rejected)
2535 return;
2536 QString strFileName(dialog.textValue());
2537 if (strFileName.isEmpty() || strFileName.contains("..") || strFileName.contains(QDir::separator()))
2538 {
2539 sigStatusBarMessage(QString("%1 %2").arg(strFileName).arg(UISoftKeyboard::tr(" is an invalid file name")));
2540 return;
2541 }
2542
2543 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(currentLayout.physicalLayoutUuid());
2544 if (!pPhysicalLayout)
2545 {
2546 sigStatusBarMessage("The layout file could not be saved");
2547 return;
2548 }
2549
2550 QFileInfo fileInfo(strFileName);
2551 if (fileInfo.suffix().compare("xml", Qt::CaseInsensitive) != 0)
2552 strFileName += ".xml";
2553 strFileName = strHomeFolder + QString(QDir::separator()) + strFileName;
2554 QFile xmlFile(strFileName);
2555 if (!xmlFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
2556 {
2557 sigStatusBarMessage("The layout file could not be saved");
2558 return;
2559 }
2560
2561 QXmlStreamWriter xmlWriter;
2562 xmlWriter.setDevice(&xmlFile);
2563
2564 xmlWriter.setAutoFormatting(true);
2565 xmlWriter.writeStartDocument("1.0");
2566 xmlWriter.writeStartElement("layout");
2567 xmlWriter.writeTextElement("name", currentLayout.name());
2568 xmlWriter.writeTextElement("nativename", currentLayout.nativeName());
2569 xmlWriter.writeTextElement("physicallayoutid", pPhysicalLayout->uid().toString());
2570 xmlWriter.writeTextElement("id", currentLayout.uid().toString());
2571
2572 QVector<UISoftKeyboardRow> &rows = pPhysicalLayout->rows();
2573 for (int i = 0; i < rows.size(); ++i)
2574 {
2575 QVector<UISoftKeyboardKey> &keys = rows[i].keys();
2576
2577 for (int j = 0; j < keys.size(); ++j)
2578 {
2579 xmlWriter.writeStartElement("key");
2580
2581 UISoftKeyboardKey &key = keys[j];
2582 xmlWriter.writeTextElement("position", QString::number(key.position()));
2583 xmlWriter.writeTextElement("basecaption", currentLayout.baseCaption(key.position()));
2584 xmlWriter.writeTextElement("shiftcaption", currentLayout.shiftCaption(key.position()));
2585 xmlWriter.writeTextElement("altgrcaption", currentLayout.altGrCaption(key.position()));
2586 xmlWriter.writeTextElement("shiftaltgrcaption", currentLayout.shiftAltGrCaption(key.position()));
2587 xmlWriter.writeEndElement();
2588 }
2589 }
2590 xmlWriter.writeEndElement();
2591 xmlWriter.writeEndDocument();
2592
2593 xmlFile.close();
2594 currentLayout.setSourceFilePath(strFileName);
2595 currentLayout.setEditedBuNotSaved(false);
2596 sigStatusBarMessage(QString("%1 %2").arg(strFileName).arg(UISoftKeyboard::tr(" is saved")));
2597}
2598
2599void UISoftKeyboardWidget::copyCurentLayout()
2600{
2601 UISoftKeyboardLayout newLayout(m_layouts[m_uCurrentLayoutId]);
2602
2603 QString strNewName = QString("%1-%2").arg(newLayout.name()).arg(UISoftKeyboard::tr("Copy"));
2604 int iCount = 1;
2605 while (layoutByNameExists(strNewName))
2606 {
2607 strNewName = QString("%1-%2-%3").arg(newLayout.name()).arg(UISoftKeyboard::tr("Copy")).arg(QString::number(iCount));
2608 ++iCount;
2609 }
2610
2611 newLayout.setName(strNewName);
2612 newLayout.setEditedBuNotSaved(true);
2613 newLayout.setEditable(true);
2614 newLayout.setIsFromResources(false);
2615 newLayout.setSourceFilePath(QString());
2616 newLayout.setUid(QUuid::createUuid());
2617 addLayout(newLayout);
2618}
2619
2620float UISoftKeyboardWidget::layoutAspectRatio()
2621{
2622 if (m_iInitialWidth == 0)
2623 return 1.f;
2624 return m_iInitialHeight / (float) m_iInitialWidth;
2625}
2626
2627bool UISoftKeyboardWidget::hideOSMenuKeys() const
2628{
2629 return m_fHideOSMenuKeys;
2630}
2631
2632void UISoftKeyboardWidget::setHideOSMenuKeys(bool fHide)
2633{
2634 if (m_fHideOSMenuKeys == fHide)
2635 return;
2636 m_fHideOSMenuKeys = fHide;
2637 update();
2638 emit sigOptionsChanged();
2639}
2640
2641bool UISoftKeyboardWidget::hideNumPad() const
2642{
2643 return m_fHideNumPad;
2644}
2645
2646void UISoftKeyboardWidget::setHideNumPad(bool fHide)
2647{
2648 if (m_fHideNumPad == fHide)
2649 return;
2650 m_fHideNumPad = fHide;
2651 update();
2652 emit sigOptionsChanged();
2653}
2654
2655bool UISoftKeyboardWidget::hideMultimediaKeys() const
2656{
2657 return m_fHideMultimediaKeys;
2658}
2659
2660void UISoftKeyboardWidget::setHideMultimediaKeys(bool fHide)
2661{
2662 if (m_fHideMultimediaKeys == fHide)
2663 return;
2664 m_fHideMultimediaKeys = fHide;
2665 update();
2666 emit sigOptionsChanged();
2667}
2668
2669QColor UISoftKeyboardWidget::color(KeyboardColorType enmColorType) const
2670{
2671 if (!m_currentColorTheme)
2672 return QColor();
2673 return m_currentColorTheme->color(enmColorType);
2674}
2675
2676void UISoftKeyboardWidget::setColor(KeyboardColorType enmColorType, const QColor &color)
2677{
2678 if (m_currentColorTheme)
2679 m_currentColorTheme->setColor(enmColorType, color);
2680 update();
2681}
2682
2683QStringList UISoftKeyboardWidget::colorsToStringList(const QString &strColorThemeName)
2684{
2685 UISoftKeyboardColorTheme *pTheme = colorTheme(strColorThemeName);
2686 if (!pTheme)
2687 return QStringList();
2688 return pTheme->colorsToStringList();
2689}
2690
2691void UISoftKeyboardWidget::colorsFromStringList(const QString &strColorThemeName, const QStringList &colorStringList)
2692{
2693 UISoftKeyboardColorTheme *pTheme = colorTheme(strColorThemeName);
2694 if (!pTheme)
2695 return;
2696 pTheme->colorsFromStringList(colorStringList);
2697}
2698
2699void UISoftKeyboardWidget::updateLockKeyStates(bool fCapsLockState, bool fNumLockState, bool fScrollLockState)
2700{
2701 for (int i = 0; i < m_physicalLayouts.size(); ++i)
2702 m_physicalLayouts[i].updateLockKeyStates(fCapsLockState, fNumLockState, fScrollLockState);
2703 update();
2704}
2705
2706QStringList UISoftKeyboardWidget::colorThemeNames() const
2707{
2708 QStringList nameList;
2709 foreach (const UISoftKeyboardColorTheme &theme, m_colorThemes)
2710 {
2711 nameList << theme.name();
2712 }
2713 return nameList;
2714}
2715
2716QString UISoftKeyboardWidget::currentColorThemeName() const
2717{
2718 if (!m_currentColorTheme)
2719 return QString();
2720 return m_currentColorTheme->name();
2721}
2722
2723void UISoftKeyboardWidget::setColorThemeByName(const QString &strColorThemeName)
2724{
2725 if (strColorThemeName.isEmpty())
2726 return;
2727 if (m_currentColorTheme && m_currentColorTheme->name() == strColorThemeName)
2728 return;
2729 for (int i = 0; i < m_colorThemes.size(); ++i)
2730 {
2731 if (m_colorThemes[i].name() == strColorThemeName)
2732 {
2733 m_currentColorTheme = &(m_colorThemes[i]);
2734 break;
2735 }
2736 }
2737 update();
2738 emit sigCurrentColorThemeChanged();
2739}
2740
2741void UISoftKeyboardWidget::parentDialogDeactivated()
2742{
2743 if (!underMouse())
2744 m_pKeyUnderMouse = 0;
2745 update();
2746}
2747
2748bool UISoftKeyboardWidget::isColorThemeEditable() const
2749{
2750 if (!m_currentColorTheme)
2751 return false;
2752 return m_currentColorTheme->isEditable();
2753}
2754
2755QStringList UISoftKeyboardWidget::unsavedLayoutsNameList() const
2756{
2757 QStringList nameList;
2758 foreach (const UISoftKeyboardLayout &layout, m_layouts)
2759 {
2760 if (layout.editedButNotSaved())
2761 nameList << layout.nameString();
2762 }
2763 return nameList;
2764}
2765
2766void UISoftKeyboardWidget::deleteCurrentLayout()
2767{
2768 if (!m_layouts.contains(m_uCurrentLayoutId))
2769 return;
2770
2771 /* Make sure we will have at least one layout remaining. */
2772 if (m_layouts.size() <= 1)
2773 return;
2774
2775 const UISoftKeyboardLayout &layout = m_layouts.value(m_uCurrentLayoutId);
2776 if (!layout.editable() || layout.isFromResources())
2777 return;
2778
2779 QDir fileToDelete;
2780 QString strFilePath(layout.sourceFilePath());
2781
2782 bool fFileExists = false;
2783 if (!strFilePath.isEmpty())
2784 fFileExists = fileToDelete.exists(strFilePath);
2785 /* It might be that the layout copied but not yet saved into a file: */
2786 if (fFileExists)
2787 {
2788 if (!msgCenter().questionBinary(this, MessageType_Question,
2789 QString(UISoftKeyboard::tr("This will delete the keyboard layout file as well. Proceed?")),
2790 0 /* auto-confirm id */,
2791 QString("Delete") /* ok button text */,
2792 QString() /* cancel button text */,
2793 false /* ok button by default? */))
2794 return;
2795
2796 if (fileToDelete.remove(strFilePath))
2797 sigStatusBarMessage(UISoftKeyboard::tr("The file %1 has been deleted").arg(strFilePath));
2798 else
2799 sigStatusBarMessage(UISoftKeyboard::tr("Deleting the file %1 has failed").arg(strFilePath));
2800 }
2801
2802 m_layouts.remove(m_uCurrentLayoutId);
2803 setCurrentLayout(m_layouts.firstKey());
2804}
2805
2806void UISoftKeyboardWidget::toggleEditMode(bool fIsEditMode)
2807{
2808 if (fIsEditMode)
2809 m_enmMode = Mode_LayoutEdit;
2810 else
2811 {
2812 m_enmMode = Mode_Keyboard;
2813 m_pKeyBeingEdited = 0;
2814 }
2815 update();
2816}
2817
2818void UISoftKeyboardWidget::addLayout(const UISoftKeyboardLayout &newLayout)
2819{
2820 if (m_layouts.contains(newLayout.uid()))
2821 return;
2822 m_layouts[newLayout.uid()] = newLayout;
2823}
2824
2825void UISoftKeyboardWidget::setNewMinimumSize(const QSize &size)
2826{
2827 m_minimumSize = size;
2828 updateGeometry();
2829}
2830
2831void UISoftKeyboardWidget::setInitialSize(int iWidth, int iHeight)
2832{
2833 m_iInitialWidth = iWidth;
2834 m_iInitialHeight = iHeight;
2835}
2836
2837UISoftKeyboardKey *UISoftKeyboardWidget::keyUnderMouse(QMouseEvent *pEvent)
2838{
2839 const QPoint lPos = pEvent->position().toPoint();
2840 QPoint eventPosition(lPos.x() / m_fScaleFactorX, lPos.y() / m_fScaleFactorY);
2841 if (m_fHideMultimediaKeys)
2842 eventPosition.setY(eventPosition.y() + m_multiMediaKeysLayout.totalHeight());
2843 return keyUnderMouse(eventPosition);
2844}
2845
2846UISoftKeyboardKey *UISoftKeyboardWidget::keyUnderMouse(const QPoint &eventPosition)
2847{
2848 const UISoftKeyboardLayout &currentLayout = m_layouts.value(m_uCurrentLayoutId);
2849
2850 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(currentLayout.physicalLayoutUuid());
2851 if (!pPhysicalLayout)
2852 return 0;
2853
2854 UISoftKeyboardKey *pKey = 0;
2855 QVector<UISoftKeyboardRow> &rows = pPhysicalLayout->rows();
2856 for (int i = 0; i < rows.size(); ++i)
2857 {
2858 QVector<UISoftKeyboardKey> &keys = rows[i].keys();
2859 for (int j = 0; j < keys.size(); ++j)
2860 {
2861 UISoftKeyboardKey &key = keys[j];
2862 if (key.polygonInGlobal().containsPoint(eventPosition, Qt::OddEvenFill))
2863 {
2864 pKey = &key;
2865 break;
2866 }
2867 }
2868 }
2869 if (m_pKeyUnderMouse != pKey)
2870 {
2871 m_pKeyUnderMouse = pKey;
2872 update();
2873 }
2874 return pKey;
2875}
2876
2877void UISoftKeyboardWidget::handleKeyRelease(UISoftKeyboardKey *pKey)
2878{
2879 if (!pKey)
2880 return;
2881 if (pKey->type() == KeyType_Ordinary)
2882 pKey->release();
2883 /* We only send the scan codes of Ordinary keys: */
2884 if (pKey->type() == KeyType_Modifier)
2885 return;
2886
2887#if 0
2888
2889 QVector<LONG> sequence;
2890 if (!pKey->scanCodePrefix().isEmpty())
2891 sequence << pKey->scanCodePrefix();
2892 sequence << (pKey->scanCode() | 0x80);
2893
2894 /* Add the pressed modifiers in the reverse order: */
2895 for (int i = m_pressedModifiers.size() - 1; i >= 0; --i)
2896 {
2897 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2898 if (!pModifier->scanCodePrefix().isEmpty())
2899 sequence << pModifier->scanCodePrefix();
2900 sequence << (pModifier->scanCode() | 0x80);
2901 /* Release the pressed modifiers (if there are not locked): */
2902 pModifier->release();
2903 }
2904 putKeyboardSequence(sequence);
2905
2906#else
2907
2908 QVector<QPair<LONG, LONG> > sequence;
2909 sequence << QPair<LONG, LONG>(pKey->usagePageIdPair());
2910 /* Add the pressed modifiers in the reverse order: */
2911 for (int i = m_pressedModifiers.size() - 1; i >= 0; --i)
2912 {
2913 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2914 sequence << pModifier->usagePageIdPair();
2915 /* Release the pressed modifiers (if there are not locked): */
2916 pModifier->release();
2917 }
2918 putUsageCodesRelease(sequence);
2919
2920#endif
2921}
2922
2923void UISoftKeyboardWidget::handleKeyPress(UISoftKeyboardKey *pKey)
2924{
2925 if (!pKey)
2926 return;
2927 pKey->press();
2928
2929 if (pKey->type() == KeyType_Modifier)
2930 return;
2931
2932#if 0
2933 QVector<LONG> sequence;
2934 /* Add the pressed modifiers first: */
2935 for (int i = 0; i < m_pressedModifiers.size(); ++i)
2936 {
2937 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2938 if (!pModifier->scanCodePrefix().isEmpty())
2939 sequence << pModifier->scanCodePrefix();
2940 sequence << pModifier->scanCode();
2941 }
2942
2943 if (!pKey->scanCodePrefix().isEmpty())
2944 sequence << pKey->scanCodePrefix();
2945 sequence << pKey->scanCode();
2946 putKeyboardSequence(sequence);
2947
2948#else
2949
2950 QVector<QPair<LONG, LONG> > sequence;
2951
2952 /* Add the pressed modifiers first: */
2953 for (int i = 0; i < m_pressedModifiers.size(); ++i)
2954 {
2955 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2956 sequence << pModifier->usagePageIdPair();
2957 }
2958
2959 sequence << pKey->usagePageIdPair();
2960 putUsageCodesPress(sequence);
2961
2962#endif
2963}
2964
2965void UISoftKeyboardWidget::modifierKeyPressRelease(UISoftKeyboardKey *pKey, bool fRelease)
2966{
2967 if (!pKey || pKey->type() != KeyType_Modifier)
2968 return;
2969
2970 pKey->setState(KeyState_NotPressed);
2971
2972 QVector<QPair<LONG, LONG> > sequence;
2973 sequence << pKey->usagePageIdPair();
2974 if (fRelease)
2975 putUsageCodesRelease(sequence);
2976 else
2977 putUsageCodesPress(sequence);
2978}
2979
2980void UISoftKeyboardWidget::keyStateChange(UISoftKeyboardKey* pKey)
2981{
2982 if (!pKey)
2983 return;
2984 if (pKey->type() == KeyType_Modifier)
2985 {
2986 if (pKey->state() == KeyState_NotPressed)
2987 m_pressedModifiers.removeOne(pKey);
2988 else
2989 if (!m_pressedModifiers.contains(pKey))
2990 m_pressedModifiers.append(pKey);
2991 }
2992}
2993
2994void UISoftKeyboardWidget::setCurrentLayout(const QUuid &layoutUid)
2995{
2996 if (m_uCurrentLayoutId == layoutUid || !m_layouts.contains(layoutUid))
2997 return;
2998
2999 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(m_layouts[layoutUid].physicalLayoutUuid());
3000 if (!pPhysicalLayout)
3001 return;
3002
3003 m_uCurrentLayoutId = layoutUid;
3004 emit sigCurrentLayoutChange();
3005 update();
3006}
3007
3008UISoftKeyboardLayout *UISoftKeyboardWidget::currentLayout()
3009{
3010 if (!m_layouts.contains(m_uCurrentLayoutId))
3011 return 0;
3012 return &(m_layouts[m_uCurrentLayoutId]);
3013}
3014
3015bool UISoftKeyboardWidget::loadPhysicalLayout(const QString &strLayoutFileName, KeyboardRegion keyboardRegion /* = KeyboardRegion_Main */)
3016{
3017 if (strLayoutFileName.isEmpty())
3018 return false;
3019 UIPhysicalLayoutReader reader;
3020 UISoftKeyboardPhysicalLayout *newPhysicalLayout = 0;
3021 if (keyboardRegion == KeyboardRegion_Main)
3022 {
3023 m_physicalLayouts.append(UISoftKeyboardPhysicalLayout());
3024 newPhysicalLayout = &(m_physicalLayouts.back());
3025 }
3026 else if (keyboardRegion == KeyboardRegion_NumPad)
3027 newPhysicalLayout = &(m_numPadLayout);
3028 else if (keyboardRegion == KeyboardRegion_MultimediaKeys)
3029 newPhysicalLayout = &(m_multiMediaKeysLayout);
3030 else
3031 return false;
3032
3033 if (!reader.parseXMLFile(strLayoutFileName, *newPhysicalLayout))
3034 {
3035 m_physicalLayouts.removeLast();
3036 return false;
3037 }
3038
3039 for (int i = 0; i < newPhysicalLayout->rows().size(); ++i)
3040 {
3041 UISoftKeyboardRow &row = newPhysicalLayout->rows()[i];
3042 for (int j = 0; j < row.keys().size(); ++j)
3043 row.keys()[j].setKeyboardRegion(keyboardRegion);
3044 }
3045
3046 if (keyboardRegion == KeyboardRegion_NumPad || keyboardRegion == KeyboardRegion_MultimediaKeys)
3047 return true;
3048
3049 /* Go thru all the keys row by row and construct their geometries: */
3050 int iY = m_iTopMargin;
3051 int iMaxWidth = 0;
3052 int iMaxWidthNoNumPad = 0;
3053 const QVector<UISoftKeyboardRow> &numPadRows = m_numPadLayout.rows();
3054 QVector<UISoftKeyboardRow> &rows = newPhysicalLayout->rows();
3055
3056 /* Prepend the multimedia rows to the layout */
3057 const QVector<UISoftKeyboardRow> &multimediaRows = m_multiMediaKeysLayout.rows();
3058 for (int i = multimediaRows.size() - 1; i >= 0; --i)
3059 rows.prepend(multimediaRows[i]);
3060
3061 for (int i = 0; i < rows.size(); ++i)
3062 {
3063 UISoftKeyboardRow &row = rows[i];
3064 /* Insert the numpad rows at the end of keyboard rows starting with appending 0th numpad row to the
3065 end of (1 + multimediaRows.size())th layout row: */
3066 if (i > multimediaRows.size())
3067 {
3068 int iNumPadRowIndex = i - (1 + multimediaRows.size());
3069 if (iNumPadRowIndex >= 0 && iNumPadRowIndex < numPadRows.size())
3070 {
3071 for (int m = 0; m < numPadRows[iNumPadRowIndex].keys().size(); ++m)
3072 row.keys().append(numPadRows[iNumPadRowIndex].keys()[m]);
3073 }
3074 }
3075
3076 int iX = m_iLeftMargin + row.leftMargin();
3077 int iXNoNumPad = m_iLeftMargin;
3078 int iRowHeight = row.defaultHeight();
3079 int iKeyWidth = 0;
3080 for (int j = 0; j < row.keys().size(); ++j)
3081 {
3082 UISoftKeyboardKey &key = (row.keys())[j];
3083 if (key.position() == iScrollLockPosition ||
3084 key.position() == iNumLockPosition ||
3085 key.position() == iCapsLockPosition)
3086 newPhysicalLayout->setLockKey(key.position(), &key);
3087
3088 if (key.keyboardRegion() == KeyboardRegion_NumPad)
3089 key.setKeyGeometry(QRect(iX + m_iBeforeNumPadWidth, iY, key.width(), key.height()));
3090 else
3091 key.setKeyGeometry(QRect(iX, iY, key.width(), key.height()));
3092
3093 key.setCornerRadius(0.1 * newPhysicalLayout->defaultKeyWidth());
3094 key.setPoints(UIPhysicalLayoutReader::computeKeyVertices(key));
3095 key.setParentWidget(this);
3096
3097 iKeyWidth = key.width();
3098 if (j < row.keys().size() - 1)
3099 iKeyWidth += m_iXSpacing;
3100 if (key.spaceWidthAfter() != 0 && j != row.keys().size() - 1)
3101 iKeyWidth += (m_iXSpacing + key.spaceWidthAfter());
3102
3103 iX += iKeyWidth;
3104 if (key.keyboardRegion() != KeyboardRegion_NumPad)
3105 iXNoNumPad += iKeyWidth;
3106 }
3107 if (row.spaceHeightAfter() != 0)
3108 iY += row.spaceHeightAfter() + m_iYSpacing;
3109 iMaxWidth = qMax(iMaxWidth, iX);
3110 iMaxWidthNoNumPad = qMax(iMaxWidthNoNumPad, iXNoNumPad);
3111
3112 iY += iRowHeight;
3113 if (i < rows.size() - 1)
3114 iY += m_iYSpacing;
3115 }
3116 int iInitialWidth = iMaxWidth + m_iRightMargin;
3117 int iInitialWidthNoNumPad = iMaxWidthNoNumPad + m_iRightMargin;
3118 int iInitialHeight = iY + m_iBottomMargin;
3119 m_iInitialWidth = qMax(m_iInitialWidth, iInitialWidth);
3120 m_iInitialWidthNoNumPad = qMax(m_iInitialWidthNoNumPad, iInitialWidthNoNumPad);
3121 m_iInitialHeight = qMax(m_iInitialHeight, iInitialHeight);
3122 return true;
3123}
3124
3125bool UISoftKeyboardWidget::loadKeyboardLayout(const QString &strLayoutFileName)
3126{
3127 if (strLayoutFileName.isEmpty())
3128 return false;
3129
3130 UIKeyboardLayoutReader keyboardLayoutReader;
3131
3132 UISoftKeyboardLayout newLayout;
3133 if (!keyboardLayoutReader.parseFile(strLayoutFileName, newLayout))
3134 return false;
3135
3136 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(newLayout.physicalLayoutUuid());
3137 /* If no pyhsical layout with the UUID the keyboard layout refers is found then cancel loading the keyboard layout: */
3138 if (!pPhysicalLayout)
3139 return false;
3140
3141 /* Make sure we have unique lay1out UUIDs: */
3142 int iCount = 0;
3143 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3144 {
3145 if (layout.uid() == newLayout.uid())
3146 ++iCount;
3147 }
3148 if (iCount > 1)
3149 return false;
3150
3151 newLayout.setSourceFilePath(strLayoutFileName);
3152 addLayout(newLayout);
3153 return true;
3154}
3155
3156UISoftKeyboardPhysicalLayout *UISoftKeyboardWidget::findPhysicalLayout(const QUuid &uuid)
3157{
3158 for (int i = 0; i < m_physicalLayouts.size(); ++i)
3159 {
3160 if (m_physicalLayouts[i].uid() == uuid)
3161 return &(m_physicalLayouts[i]);
3162 }
3163 return 0;
3164}
3165
3166void UISoftKeyboardWidget::reset()
3167{
3168 m_pressedModifiers.clear();
3169 m_pKeyUnderMouse = 0;
3170 m_pKeyBeingEdited = 0;
3171 m_pKeyPressed = 0;
3172 m_enmMode = Mode_Keyboard;
3173
3174 for (int i = 0; i < m_physicalLayouts.size(); ++i)
3175 m_physicalLayouts[i].reset();
3176}
3177
3178void UISoftKeyboardWidget::loadLayouts()
3179{
3180 /* Load physical layouts from resources: Numpad and multimedia layout files should be read first
3181 since we insert these to other layouts: */
3182 loadPhysicalLayout(":/numpad.xml", KeyboardRegion_NumPad);
3183 loadPhysicalLayout(":/multimedia_keys.xml", KeyboardRegion_MultimediaKeys);
3184 QStringList physicalLayoutNames;
3185 physicalLayoutNames << ":/101_ansi.xml"
3186 << ":/102_iso.xml"
3187 << ":/106_japanese.xml"
3188 << ":/103_iso.xml"
3189 << ":/103_ansi.xml";
3190 foreach (const QString &strName, physicalLayoutNames)
3191 loadPhysicalLayout(strName);
3192
3193 setNewMinimumSize(QSize(m_iInitialWidth, m_iInitialHeight));
3194 setInitialSize(m_iInitialWidth, m_iInitialHeight);
3195
3196 /* Add keyboard layouts from resources: */
3197 QStringList keyboardLayoutNames;
3198 keyboardLayoutNames << ":/us_international.xml"
3199 << ":/german.xml"
3200 << ":/us.xml"
3201 << ":/greek.xml"
3202 << ":/japanese.xml"
3203 << ":/brazilian.xml"
3204 << ":/korean.xml";
3205
3206 foreach (const QString &strName, keyboardLayoutNames)
3207 loadKeyboardLayout(strName);
3208 /* Mark the layouts we load from the resources as non-editable: */
3209 for (QMap<QUuid, UISoftKeyboardLayout>::iterator iterator = m_layouts.begin(); iterator != m_layouts.end(); ++iterator)
3210 {
3211 iterator.value().setEditable(false);
3212 iterator.value().setIsFromResources(true);
3213 }
3214 keyboardLayoutNames.clear();
3215 /* Add keyboard layouts from the defalt keyboard layout folder: */
3216 lookAtDefaultLayoutFolder(keyboardLayoutNames);
3217 foreach (const QString &strName, keyboardLayoutNames)
3218 loadKeyboardLayout(strName);
3219
3220 if (m_layouts.isEmpty())
3221 return;
3222 for (QMap<QUuid, UISoftKeyboardLayout>::iterator iterator = m_layouts.begin(); iterator != m_layouts.end(); ++iterator)
3223 iterator.value().setEditedBuNotSaved(false);
3224 /* Block sigCurrentLayoutChange since it causes saving set layout to exra data: */
3225 blockSignals(true);
3226 setCurrentLayout(m_layouts.firstKey());
3227 blockSignals(false);
3228}
3229
3230void UISoftKeyboardWidget::prepareObjects()
3231{
3232 setMouseTracking(true);
3233 connect(m_pMachine, &UIMachine::sigKeyboardLedsChange, this, &UISoftKeyboardWidget::sltKeyboardLedsChange);
3234}
3235
3236void UISoftKeyboardWidget::prepareColorThemes()
3237{
3238 int iIndex = 0;
3239 while (predefinedColorThemes[iIndex][0])
3240 {
3241 m_colorThemes << UISoftKeyboardColorTheme(predefinedColorThemes[iIndex][0],
3242 predefinedColorThemes[iIndex][1],
3243 predefinedColorThemes[iIndex][2],
3244 predefinedColorThemes[iIndex][3],
3245 predefinedColorThemes[iIndex][4],
3246 predefinedColorThemes[iIndex][5]);
3247 ++iIndex;
3248 }
3249
3250 UISoftKeyboardColorTheme customTheme;
3251 customTheme.setName("Custom");
3252 customTheme.setIsEditable(true);
3253 m_colorThemes.append(customTheme);
3254 m_currentColorTheme = &(m_colorThemes.back());
3255}
3256
3257void UISoftKeyboardWidget::setKeyBeingEdited(UISoftKeyboardKey* pKey)
3258{
3259 if (m_pKeyBeingEdited == pKey)
3260 return;
3261 m_pKeyBeingEdited = pKey;
3262 emit sigKeyToEdit(pKey);
3263}
3264
3265bool UISoftKeyboardWidget::layoutByNameExists(const QString &strName) const
3266{
3267 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3268 {
3269 if (layout.name() == strName)
3270 return true;
3271 }
3272 return false;
3273}
3274
3275void UISoftKeyboardWidget::lookAtDefaultLayoutFolder(QStringList &fileList)
3276{
3277 QString strFolder = QString("%1%2%3").arg(gpGlobalSession->homeFolder()).arg(QDir::separator()).arg(strSubDirectorName);
3278 QDir dir(strFolder);
3279 if (!dir.exists())
3280 return;
3281 QStringList filters;
3282 filters << "*.xml";
3283 dir.setNameFilters(filters);
3284 QFileInfoList fileInfoList = dir.entryInfoList();
3285 foreach (const QFileInfo &fileInfo, fileInfoList)
3286 fileList << fileInfo.absoluteFilePath();
3287}
3288
3289UISoftKeyboardColorTheme *UISoftKeyboardWidget::colorTheme(const QString &strColorThemeName)
3290{
3291 for (int i = 0; i < m_colorThemes.size(); ++i)
3292 {
3293 if (m_colorThemes[i].name() == strColorThemeName)
3294 return &(m_colorThemes[i]);
3295 }
3296 return 0;
3297}
3298
3299void UISoftKeyboardWidget::showKeyTooltip(UISoftKeyboardKey *pKey)
3300{
3301 if (pKey && m_keyTooltips.contains(pKey->position()))
3302 sigStatusBarMessage(m_keyTooltips[pKey->position()]);
3303 else
3304 sigStatusBarMessage(QString());
3305
3306}
3307
3308QStringList UISoftKeyboardWidget::layoutNameList() const
3309{
3310 QStringList layoutNames;
3311 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3312 layoutNames << layout.nameString();
3313 return layoutNames;
3314}
3315
3316QList<QUuid> UISoftKeyboardWidget::layoutUidList() const
3317{
3318 QList<QUuid> layoutUids;
3319 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3320 layoutUids << layout.uid();
3321 return layoutUids;
3322}
3323
3324const QVector<UISoftKeyboardPhysicalLayout> &UISoftKeyboardWidget::physicalLayouts() const
3325{
3326 return m_physicalLayouts;
3327}
3328
3329void UISoftKeyboardWidget::sltKeyboardLedsChange()
3330{
3331 if (m_pMachine)
3332 {
3333 bool fNumLockLed = m_pMachine->isNumLock();
3334 bool fCapsLockLed = m_pMachine->isCapsLock();
3335 bool fScrollLockLed = m_pMachine->isScrollLock();
3336 updateLockKeyStates(fCapsLockLed, fNumLockLed, fScrollLockLed);
3337 }
3338}
3339
3340void UISoftKeyboardWidget::putKeyboardSequence(QVector<LONG> sequence)
3341{
3342 if (m_pMachine)
3343 m_pMachine->putScancodes(sequence);
3344}
3345
3346void UISoftKeyboardWidget::putUsageCodesPress(QVector<QPair<LONG, LONG> > sequence)
3347{
3348 if (m_pMachine)
3349 {
3350 for (int i = 0; i < sequence.size(); ++i)
3351 m_pMachine->putUsageCode(sequence[i].first, sequence[i].second, false);
3352 }
3353}
3354
3355void UISoftKeyboardWidget::putUsageCodesRelease(QVector<QPair<LONG, LONG> > sequence)
3356{
3357 if (m_pMachine)
3358 {
3359 for (int i = 0; i < sequence.size(); ++i)
3360 m_pMachine->putUsageCode(sequence[i].first, sequence[i].second, true);
3361 }
3362}
3363
3364
3365/*********************************************************************************************************************************
3366* UIPhysicalLayoutReader implementation. *
3367*********************************************************************************************************************************/
3368
3369bool UIPhysicalLayoutReader::parseXMLFile(const QString &strFileName, UISoftKeyboardPhysicalLayout &physicalLayout)
3370{
3371 QFile xmlFile(strFileName);
3372 if (!xmlFile.exists())
3373 return false;
3374
3375 if (xmlFile.size() >= iFileSizeLimit)
3376 return false;
3377
3378 if (!xmlFile.open(QIODevice::ReadOnly))
3379 return false;
3380
3381 m_xmlReader.setDevice(&xmlFile);
3382
3383 if (!m_xmlReader.readNextStartElement() || m_xmlReader.name() != QLatin1String("physicallayout"))
3384 return false;
3385 physicalLayout.setFileName(strFileName);
3386
3387 QXmlStreamAttributes attributes = m_xmlReader.attributes();
3388 int iDefaultWidth = attributes.value("defaultWidth").toInt();
3389 int iDefaultHeight = attributes.value("defaultHeight").toInt();
3390 QVector<UISoftKeyboardRow> &rows = physicalLayout.rows();
3391 physicalLayout.setDefaultKeyWidth(iDefaultWidth);
3392
3393 while (m_xmlReader.readNextStartElement())
3394 {
3395 if (m_xmlReader.name() == QLatin1String("row"))
3396 parseRow(iDefaultWidth, iDefaultHeight, rows);
3397 else if (m_xmlReader.name() == QLatin1String("name"))
3398 physicalLayout.setName(m_xmlReader.readElementText());
3399 else if (m_xmlReader.name() == QLatin1String("id"))
3400 physicalLayout.setUid(QUuid(m_xmlReader.readElementText()));
3401 else
3402 m_xmlReader.skipCurrentElement();
3403 }
3404
3405 return true;
3406}
3407
3408void UIPhysicalLayoutReader::parseRow(int iDefaultWidth, int iDefaultHeight, QVector<UISoftKeyboardRow> &rows)
3409{
3410 rows.append(UISoftKeyboardRow());
3411 UISoftKeyboardRow &row = rows.back();
3412
3413 row.setDefaultWidth(iDefaultWidth);
3414 row.setDefaultHeight(iDefaultHeight);
3415 row.setSpaceHeightAfter(0);
3416
3417 /* Override the layout attributes if the row also has them: */
3418 QXmlStreamAttributes attributes = m_xmlReader.attributes();
3419 if (attributes.hasAttribute("defaultWidth"))
3420 row.setDefaultWidth(attributes.value("defaultWidth").toInt());
3421 if (attributes.hasAttribute("defaultHeight"))
3422 row.setDefaultHeight(attributes.value("defaultHeight").toInt());
3423 while (m_xmlReader.readNextStartElement())
3424 {
3425 if (m_xmlReader.name() == QLatin1String("key"))
3426 parseKey(row);
3427 else if (m_xmlReader.name() == QLatin1String("space"))
3428 parseKeySpace(row);
3429 else
3430 m_xmlReader.skipCurrentElement();
3431 }
3432}
3433
3434void UIPhysicalLayoutReader::parseKey(UISoftKeyboardRow &row)
3435{
3436 row.keys().append(UISoftKeyboardKey());
3437 UISoftKeyboardKey &key = row.keys().back();
3438 key.setWidth(row.defaultWidth());
3439 key.setHeight(row.defaultHeight());
3440 QString strKeyCap;
3441 while (m_xmlReader.readNextStartElement())
3442 {
3443 if (m_xmlReader.name() == QLatin1String("width"))
3444 key.setWidth(m_xmlReader.readElementText().toInt());
3445 else if (m_xmlReader.name() == QLatin1String("height"))
3446 key.setHeight(m_xmlReader.readElementText().toInt());
3447 else if (m_xmlReader.name() == QLatin1String("scancode"))
3448 {
3449 QString strCode = m_xmlReader.readElementText();
3450 bool fOk = false;
3451 key.setScanCode(strCode.toInt(&fOk, 16));
3452 }
3453 else if (m_xmlReader.name() == QLatin1String("scancodeprefix"))
3454 {
3455 const QString strCode = m_xmlReader.readElementText();
3456 foreach (const QString &strPrefix, strCode.split('-', Qt::SkipEmptyParts))
3457 {
3458 bool fOk = false;
3459 LONG iCode = strPrefix.toInt(&fOk, 16);
3460 if (fOk)
3461 key.addScanCodePrefix(iCode);
3462 }
3463 }
3464 else if (m_xmlReader.name() == QLatin1String("usageid"))
3465 {
3466 QString strCode = m_xmlReader.readElementText();
3467 bool fOk = false;
3468 key.setUsageId(strCode.toInt(&fOk, 16));
3469 }
3470 else if (m_xmlReader.name() == QLatin1String("usagepage"))
3471 {
3472 QString strCode = m_xmlReader.readElementText();
3473 bool fOk = false;
3474 key.setUsagePage(strCode.toInt(&fOk, 16));
3475 }
3476 else if (m_xmlReader.name() == QLatin1String("cutout"))
3477 parseCutout(key);
3478 else if (m_xmlReader.name() == QLatin1String("position"))
3479 key.setPosition(m_xmlReader.readElementText().toInt());
3480 else if (m_xmlReader.name() == QLatin1String("type"))
3481 {
3482 QString strType = m_xmlReader.readElementText();
3483 if (strType == "modifier")
3484 key.setType(KeyType_Modifier);
3485 else if (strType == "lock")
3486 key.setType(KeyType_Lock);
3487 }
3488 else if (m_xmlReader.name() == QLatin1String("osmenukey"))
3489 {
3490 if (m_xmlReader.readElementText() == "true")
3491 key.setIsOSMenuKey(true);
3492 }
3493 else if (m_xmlReader.name() == QLatin1String("staticcaption"))
3494 key.setStaticCaption(m_xmlReader.readElementText());
3495 else if (m_xmlReader.name() == QLatin1String("image"))
3496 key.setImageByName(m_xmlReader.readElementText());
3497 else
3498 m_xmlReader.skipCurrentElement();
3499 }
3500}
3501
3502void UIPhysicalLayoutReader::parseKeySpace(UISoftKeyboardRow &row)
3503{
3504 int iWidth = row.defaultWidth();
3505 int iHeight = 0;
3506 while (m_xmlReader.readNextStartElement())
3507 {
3508 if (m_xmlReader.name() == QLatin1String("width"))
3509 iWidth = m_xmlReader.readElementText().toInt();
3510 else if (m_xmlReader.name() == QLatin1String("height"))
3511 iHeight = m_xmlReader.readElementText().toInt();
3512 else
3513 m_xmlReader.skipCurrentElement();
3514 }
3515 row.setSpaceHeightAfter(iHeight);
3516 /* If we have keys add the parsed space to the last key as the 'space after': */
3517 if (!row.keys().empty())
3518 row.keys().back().setSpaceWidthAfter(iWidth);
3519 /* If we have no keys than this is the initial space left to first key: */
3520 else
3521 row.setLeftMargin(iWidth);
3522}
3523
3524void UIPhysicalLayoutReader::parseCutout(UISoftKeyboardKey &key)
3525{
3526 int iWidth = 0;
3527 int iHeight = 0;
3528 int iCorner = 0;
3529 while (m_xmlReader.readNextStartElement())
3530 {
3531 if (m_xmlReader.name() == QLatin1String("width"))
3532 iWidth = m_xmlReader.readElementText().toInt();
3533 else if (m_xmlReader.name() == QLatin1String("height"))
3534 iHeight = m_xmlReader.readElementText().toInt();
3535 else if (m_xmlReader.name() == QLatin1String("corner"))
3536 {
3537 QString strCorner = m_xmlReader.readElementText();
3538 if (strCorner == "topLeft")
3539 iCorner = 0;
3540 else if(strCorner == "topRight")
3541 iCorner = 1;
3542 else if(strCorner == "bottomRight")
3543 iCorner = 2;
3544 else if(strCorner == "bottomLeft")
3545 iCorner = 3;
3546 }
3547 else
3548 m_xmlReader.skipCurrentElement();
3549 }
3550 key.setCutout(iCorner, iWidth, iHeight);
3551}
3552
3553QVector<QPointF> UIPhysicalLayoutReader::computeKeyVertices(const UISoftKeyboardKey &key)
3554{
3555 QVector<QPointF> vertices;
3556
3557 if (key.cutoutCorner() == -1 || key.width() <= key.cutoutWidth() || key.height() <= key.cutoutHeight())
3558 {
3559 vertices.append(QPoint(0, 0));
3560 vertices.append(QPoint(key.width(), 0));
3561 vertices.append(QPoint(key.width(), key.height()));
3562 vertices.append(QPoint(0, key.height()));
3563 return vertices;
3564 }
3565 if (key.cutoutCorner() == 0)
3566 {
3567 vertices.append(QPoint(key.cutoutWidth(), 0));
3568 vertices.append(QPoint(key.width(), 0));
3569 vertices.append(QPoint(key.width(), key.height()));
3570 vertices.append(QPoint(0, key.height()));
3571 vertices.append(QPoint(0, key.cutoutHeight()));
3572 vertices.append(QPoint(key.cutoutWidth(), key.cutoutHeight()));
3573 }
3574 else if (key.cutoutCorner() == 1)
3575 {
3576 vertices.append(QPoint(0, 0));
3577 vertices.append(QPoint(key.width() - key.cutoutWidth(), 0));
3578 vertices.append(QPoint(key.width() - key.cutoutWidth(), key.cutoutHeight()));
3579 vertices.append(QPoint(key.width(), key.cutoutHeight()));
3580 vertices.append(QPoint(key.width(), key.height()));
3581 vertices.append(QPoint(0, key.height()));
3582 }
3583 else if (key.cutoutCorner() == 2)
3584 {
3585 vertices.append(QPoint(0, 0));
3586 vertices.append(QPoint(key.width(), 0));
3587 vertices.append(QPoint(key.width(), key.cutoutHeight()));
3588 vertices.append(QPoint(key.width() - key.cutoutWidth(), key.cutoutHeight()));
3589 vertices.append(QPoint(key.width() - key.cutoutWidth(), key.height()));
3590 vertices.append(QPoint(0, key.height()));
3591 }
3592 else if (key.cutoutCorner() == 3)
3593 {
3594 vertices.append(QPoint(0, 0));
3595 vertices.append(QPoint(key.width(), 0));
3596 vertices.append(QPoint(key.width(), key.height()));
3597 vertices.append(QPoint(key.cutoutWidth(), key.height()));
3598 vertices.append(QPoint(key.cutoutWidth(), key.height() - key.cutoutHeight()));
3599 vertices.append(QPoint(0, key.height() - key.cutoutHeight()));
3600 }
3601 return vertices;
3602}
3603
3604
3605/*********************************************************************************************************************************
3606* UIKeyboardLayoutReader implementation. *
3607*********************************************************************************************************************************/
3608
3609bool UIKeyboardLayoutReader::parseFile(const QString &strFileName, UISoftKeyboardLayout &layout)
3610{
3611 QFile xmlFile(strFileName);
3612 if (!xmlFile.exists())
3613 return false;
3614
3615 if (xmlFile.size() >= iFileSizeLimit)
3616 return false;
3617
3618 if (!xmlFile.open(QIODevice::ReadOnly))
3619 return false;
3620
3621 m_xmlReader.setDevice(&xmlFile);
3622
3623 if (!m_xmlReader.readNextStartElement() || m_xmlReader.name() != QLatin1String("layout"))
3624 return false;
3625
3626 while (m_xmlReader.readNextStartElement())
3627 {
3628 if (m_xmlReader.name() == QLatin1String("key"))
3629 parseKey(layout);
3630 else if (m_xmlReader.name() == QLatin1String("name"))
3631 layout.setName(m_xmlReader.readElementText());
3632 else if (m_xmlReader.name() == QLatin1String("nativename"))
3633 layout.setNativeName(m_xmlReader.readElementText());
3634 else if (m_xmlReader.name() == QLatin1String("physicallayoutid"))
3635 layout.setPhysicalLayoutUuid(QUuid(m_xmlReader.readElementText()));
3636 else if (m_xmlReader.name() == QLatin1String("id"))
3637 layout.setUid(QUuid(m_xmlReader.readElementText()));
3638 else
3639 m_xmlReader.skipCurrentElement();
3640 }
3641 return true;
3642}
3643
3644void UIKeyboardLayoutReader::parseKey(UISoftKeyboardLayout &layout)
3645{
3646 UIKeyCaptions keyCaptions;
3647 int iKeyPosition = 0;
3648 while (m_xmlReader.readNextStartElement())
3649 {
3650 if (m_xmlReader.name() == QLatin1String("basecaption"))
3651 {
3652 keyCaptions.m_strBase = m_xmlReader.readElementText();
3653 keyCaptions.m_strBase.replace("\\n", "\n");
3654 }
3655 else if (m_xmlReader.name() == QLatin1String("shiftcaption"))
3656 {
3657 keyCaptions.m_strShift = m_xmlReader.readElementText();
3658 keyCaptions.m_strShift.replace("\\n", "\n");
3659 }
3660 else if (m_xmlReader.name() == QLatin1String("altgrcaption"))
3661 {
3662 keyCaptions.m_strAltGr = m_xmlReader.readElementText();
3663 keyCaptions.m_strAltGr.replace("\\n", "\n");
3664 }
3665 else if (m_xmlReader.name() == QLatin1String("shiftaltgrcaption"))
3666 {
3667 keyCaptions.m_strShiftAltGr = m_xmlReader.readElementText();
3668 keyCaptions.m_strShiftAltGr.replace("\\n", "\n");
3669 }
3670 else if (m_xmlReader.name() == QLatin1String("position"))
3671 iKeyPosition = m_xmlReader.readElementText().toInt();
3672 else
3673 m_xmlReader.skipCurrentElement();
3674 }
3675 layout.addOrUpdateUIKeyCaptions(iKeyPosition, keyCaptions);
3676}
3677
3678
3679/*********************************************************************************************************************************
3680* UISoftKeyboardStatusBarWidget implementation. *
3681*********************************************************************************************************************************/
3682
3683UISoftKeyboardStatusBarWidget::UISoftKeyboardStatusBarWidget(QWidget *pParent /* = 0*/ )
3684 : QWidget(pParent)
3685 , m_pLayoutListButton(0)
3686 , m_pSettingsButton(0)
3687 , m_pResetButton(0)
3688 , m_pHelpButton(0)
3689 , m_pMessageLabel(0)
3690{
3691 prepareObjects();
3692}
3693
3694void UISoftKeyboardStatusBarWidget::sltRetranslateUI()
3695{
3696 if (m_pLayoutListButton)
3697 m_pLayoutListButton->setToolTip(UISoftKeyboard::tr("Layout List"));
3698 if (m_pSettingsButton)
3699 m_pSettingsButton->setToolTip(UISoftKeyboard::tr("Settings"));
3700 if (m_pResetButton)
3701 m_pResetButton->setToolTip(UISoftKeyboard::tr("Reset the keyboard and release all keys"));
3702 if (m_pHelpButton)
3703 m_pHelpButton->setToolTip(UISoftKeyboard::tr("Help"));
3704}
3705
3706void UISoftKeyboardStatusBarWidget::prepareObjects()
3707{
3708 QHBoxLayout *pLayout = new QHBoxLayout;
3709 if (!pLayout)
3710 return;
3711 pLayout->setContentsMargins(0, 0, 0, 0);
3712 setLayout(pLayout);
3713
3714 m_pMessageLabel = new QLabel;
3715 pLayout->addWidget(m_pMessageLabel);
3716
3717 m_pLayoutListButton = new QToolButton;
3718 if (m_pLayoutListButton)
3719 {
3720 m_pLayoutListButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_list_16px.png", ":/soft_keyboard_layout_list_disabled_16px.png"));
3721 m_pLayoutListButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3722 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3723 m_pLayoutListButton->resize(QSize(iIconMetric, iIconMetric));
3724 m_pLayoutListButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3725 connect(m_pLayoutListButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigShowHideSidePanel);
3726 pLayout->addWidget(m_pLayoutListButton);
3727 }
3728
3729 m_pSettingsButton = new QToolButton;
3730 if (m_pSettingsButton)
3731 {
3732 m_pSettingsButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_settings_16px.png", ":/soft_keyboard_settings_disabled_16px.png"));
3733 m_pSettingsButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3734 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3735 m_pSettingsButton->resize(QSize(iIconMetric, iIconMetric));
3736 m_pSettingsButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3737 connect(m_pSettingsButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigShowSettingWidget);
3738 pLayout->addWidget(m_pSettingsButton);
3739 }
3740
3741 m_pResetButton = new QToolButton;
3742 if (m_pResetButton)
3743 {
3744 m_pResetButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_reset_16px.png"));
3745 m_pResetButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3746 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3747 m_pResetButton->resize(QSize(iIconMetric, iIconMetric));
3748 m_pResetButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3749 connect(m_pResetButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigResetKeyboard);
3750 pLayout->addWidget(m_pResetButton);
3751 }
3752
3753 m_pHelpButton = new QToolButton;
3754 if (m_pHelpButton)
3755 {
3756 m_pHelpButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_help_16px.png"));
3757 m_pHelpButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3758 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3759 m_pHelpButton->resize(QSize(iIconMetric, iIconMetric));
3760 m_pHelpButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3761 connect(m_pHelpButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigHelpButtonPressed);
3762 pLayout->addWidget(m_pHelpButton);
3763 }
3764
3765 sltRetranslateUI();
3766
3767 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
3768 this, &UISoftKeyboardStatusBarWidget::sltRetranslateUI);
3769}
3770
3771void UISoftKeyboardStatusBarWidget::updateLayoutNameInStatusBar(const QString &strMessage)
3772{
3773 if (!m_pMessageLabel)
3774 return;
3775 m_pMessageLabel->setText(strMessage);
3776}
3777
3778
3779/*********************************************************************************************************************************
3780* UISoftKeyboardSettingsWidget implementation. *
3781*********************************************************************************************************************************/
3782
3783UISoftKeyboardSettingsWidget::UISoftKeyboardSettingsWidget(QWidget *pParent /* = 0 */)
3784 : QWidget(pParent)
3785 , m_pHideNumPadCheckBox(0)
3786 , m_pShowOsMenuButtonsCheckBox(0)
3787 , m_pHideMultimediaKeysCheckBox(0)
3788 , m_pColorThemeGroupBox(0)
3789 , m_pColorThemeComboBox(0)
3790 , m_pTitleLabel(0)
3791 , m_pCloseButton(0)
3792
3793{
3794 prepareObjects();
3795}
3796
3797void UISoftKeyboardSettingsWidget::setHideOSMenuKeys(bool fHide)
3798{
3799 if (m_pShowOsMenuButtonsCheckBox)
3800 m_pShowOsMenuButtonsCheckBox->setChecked(fHide);
3801}
3802
3803void UISoftKeyboardSettingsWidget::setHideNumPad(bool fHide)
3804{
3805 if (m_pHideNumPadCheckBox)
3806 m_pHideNumPadCheckBox->setChecked(fHide);
3807}
3808
3809void UISoftKeyboardSettingsWidget::setHideMultimediaKeys(bool fHide)
3810{
3811 if (m_pHideMultimediaKeysCheckBox)
3812 m_pHideMultimediaKeysCheckBox->setChecked(fHide);
3813}
3814
3815void UISoftKeyboardSettingsWidget::setColorSelectionButtonBackgroundAndTooltip(KeyboardColorType enmColorType,
3816 const QColor &color, bool fIsColorEditable)
3817{
3818 if (m_colorSelectLabelsButtons.size() > enmColorType && m_colorSelectLabelsButtons[enmColorType].second)
3819 {
3820 UISoftKeyboardColorButton *pButton = m_colorSelectLabelsButtons[enmColorType].second;
3821 QPalette pal = pButton->palette();
3822 pal.setColor(QPalette::Button, color);
3823 pButton->setAutoFillBackground(true);
3824 pButton->setPalette(pal);
3825 pButton->setToolTip(fIsColorEditable ? UISoftKeyboard::tr("Click to change the color.") : UISoftKeyboard::tr("This color theme is not editable."));
3826 pButton->update();
3827 }
3828}
3829
3830void UISoftKeyboardSettingsWidget::setColorThemeNames(const QStringList &colorThemeNames)
3831{
3832 if (!m_pColorThemeComboBox)
3833 return;
3834 m_pColorThemeComboBox->blockSignals(true);
3835 m_pColorThemeComboBox->clear();
3836 foreach (const QString &strName, colorThemeNames)
3837 m_pColorThemeComboBox->addItem(strName);
3838 m_pColorThemeComboBox->blockSignals(false);
3839}
3840
3841void UISoftKeyboardSettingsWidget::setCurrentColorThemeName(const QString &strColorThemeName)
3842{
3843 if (!m_pColorThemeComboBox)
3844 return;
3845 int iItemIndex = m_pColorThemeComboBox->findText(strColorThemeName, Qt::MatchFixedString);
3846 if (iItemIndex == -1)
3847 return;
3848 m_pColorThemeComboBox->blockSignals(true);
3849 m_pColorThemeComboBox->setCurrentIndex(iItemIndex);
3850 m_pColorThemeComboBox->blockSignals(false);
3851}
3852
3853void UISoftKeyboardSettingsWidget::sltRetranslateUI()
3854{
3855 if (m_pTitleLabel)
3856 m_pTitleLabel->setText(UISoftKeyboard::tr("Keyboard Settings"));
3857 if (m_pCloseButton)
3858 {
3859 m_pCloseButton->setToolTip(UISoftKeyboard::tr("Close the layout list"));
3860 m_pCloseButton->setText(UISoftKeyboard::tr("Close"));
3861 }
3862 if (m_pHideNumPadCheckBox)
3863 m_pHideNumPadCheckBox->setText(UISoftKeyboard::tr("Hide NumPad"));
3864 if (m_pShowOsMenuButtonsCheckBox)
3865 m_pShowOsMenuButtonsCheckBox->setText(UISoftKeyboard::tr("Hide OS/Menu Keys"));
3866 if (m_pHideMultimediaKeysCheckBox)
3867 m_pHideMultimediaKeysCheckBox->setText(UISoftKeyboard::tr("Hide Multimedia Keys"));
3868 if (m_pColorThemeGroupBox)
3869 m_pColorThemeGroupBox->setTitle(UISoftKeyboard::tr("Color Themes"));
3870
3871 if (m_colorSelectLabelsButtons.size() == KeyboardColorType_Max)
3872 {
3873 if (m_colorSelectLabelsButtons[KeyboardColorType_Background].first)
3874 m_colorSelectLabelsButtons[KeyboardColorType_Background].first->setText(UISoftKeyboard::tr("Button Background Color"));
3875 if (m_colorSelectLabelsButtons[KeyboardColorType_Font].first)
3876 m_colorSelectLabelsButtons[KeyboardColorType_Font].first->setText(UISoftKeyboard::tr("Button Font Color"));
3877 if (m_colorSelectLabelsButtons[KeyboardColorType_Hover].first)
3878 m_colorSelectLabelsButtons[KeyboardColorType_Hover].first->setText(UISoftKeyboard::tr("Button Hover Color"));
3879 if (m_colorSelectLabelsButtons[KeyboardColorType_Edit].first)
3880 m_colorSelectLabelsButtons[KeyboardColorType_Edit].first->setText(UISoftKeyboard::tr("Button Edit Color"));
3881 if (m_colorSelectLabelsButtons[KeyboardColorType_Pressed].first)
3882 m_colorSelectLabelsButtons[KeyboardColorType_Pressed].first->setText(UISoftKeyboard::tr("Pressed Button Font Color"));
3883 }
3884}
3885
3886void UISoftKeyboardSettingsWidget::prepareObjects()
3887{
3888 QGridLayout *pSettingsLayout = new QGridLayout;
3889 if (!pSettingsLayout)
3890 return;
3891
3892 QHBoxLayout *pTitleLayout = new QHBoxLayout;
3893 m_pCloseButton = new QToolButton;
3894 m_pCloseButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
3895 m_pCloseButton->setIcon(UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_DialogCancel));
3896 m_pCloseButton->setAutoRaise(true);
3897 connect(m_pCloseButton, &QToolButton::clicked, this, &UISoftKeyboardSettingsWidget::sigCloseSettingsWidget);
3898 m_pTitleLabel = new QLabel;
3899 pTitleLayout->addWidget(m_pTitleLabel);
3900 pTitleLayout->addStretch(2);
3901 pTitleLayout->addWidget(m_pCloseButton);
3902 pSettingsLayout->addLayout(pTitleLayout, 0, 0, 1, 2);
3903
3904 m_pHideNumPadCheckBox = new QCheckBox;
3905 m_pShowOsMenuButtonsCheckBox = new QCheckBox;
3906 m_pHideMultimediaKeysCheckBox = new QCheckBox;
3907 pSettingsLayout->addWidget(m_pHideNumPadCheckBox, 1, 0, 1, 1);
3908 pSettingsLayout->addWidget(m_pShowOsMenuButtonsCheckBox, 2, 0, 1, 1);
3909 pSettingsLayout->addWidget(m_pHideMultimediaKeysCheckBox, 3, 0, 1, 1);
3910 connect(m_pHideNumPadCheckBox, &QCheckBox::toggled, this, &UISoftKeyboardSettingsWidget::sigHideNumPad);
3911 connect(m_pShowOsMenuButtonsCheckBox, &QCheckBox::toggled, this, &UISoftKeyboardSettingsWidget::sigHideOSMenuKeys);
3912 connect(m_pHideMultimediaKeysCheckBox, &QCheckBox::toggled, this, &UISoftKeyboardSettingsWidget::sigHideMultimediaKeys);
3913
3914 /* A groupbox to host the color selection widgets: */
3915 m_pColorThemeGroupBox = new QGroupBox;
3916 QVBoxLayout *pGroupBoxLayout = new QVBoxLayout(m_pColorThemeGroupBox);
3917 pSettingsLayout->addWidget(m_pColorThemeGroupBox, 4, 0, 1, 1);
3918
3919 m_pColorThemeComboBox = new QComboBox;
3920 pGroupBoxLayout->addWidget(m_pColorThemeComboBox);
3921 connect(m_pColorThemeComboBox, &QComboBox::currentTextChanged, this, &UISoftKeyboardSettingsWidget::sigColorThemeSelectionChanged);
3922
3923 /* Creating and configuring the color selection buttons: */
3924 QGridLayout *pColorSelectionLayout = new QGridLayout;
3925 pColorSelectionLayout->setSpacing(1);
3926 pGroupBoxLayout->addLayout(pColorSelectionLayout);
3927 for (int i = KeyboardColorType_Background; i < KeyboardColorType_Max; ++i)
3928 {
3929 QLabel *pLabel = new QLabel;
3930 UISoftKeyboardColorButton *pButton = new UISoftKeyboardColorButton((KeyboardColorType)i);
3931 pButton->setFlat(true);
3932 pButton->setMaximumWidth(3 * qApp->style()->pixelMetric(QStyle::PM_LargeIconSize));
3933 pColorSelectionLayout->addWidget(pLabel, i, 0, 1, 1);
3934 pColorSelectionLayout->addWidget(pButton, i, 1, 1, 1);
3935 m_colorSelectLabelsButtons.append(ColorSelectLabelButton(pLabel, pButton));
3936 connect(pButton, &UISoftKeyboardColorButton::clicked, this, &UISoftKeyboardSettingsWidget::sltColorSelectionButtonClicked);
3937 }
3938
3939 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
3940 if (pSpacer)
3941 pSettingsLayout->addItem(pSpacer, 6, 0);
3942
3943 setLayout(pSettingsLayout);
3944 sltRetranslateUI();
3945 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
3946 this, &UISoftKeyboardSettingsWidget::sltRetranslateUI);
3947}
3948
3949void UISoftKeyboardSettingsWidget::sltColorSelectionButtonClicked()
3950{
3951 UISoftKeyboardColorButton *pButton = qobject_cast<UISoftKeyboardColorButton*>(sender());
3952 if (!pButton)
3953 return;
3954 emit sigColorCellClicked((int)pButton->colorType());
3955}
3956
3957/*********************************************************************************************************************************
3958* UISoftKeyboard implementation. *
3959*********************************************************************************************************************************/
3960
3961UISoftKeyboard::UISoftKeyboard(QWidget *pParent, UIMachine *pMachine,
3962 QWidget *pCenterWidget, QString strMachineName /* = QString() */)
3963 : QMainWindowWithRestorableGeometry(pParent)
3964 , m_pMachine(pMachine)
3965 , m_pCenterWidget(pCenterWidget)
3966 , m_pMainLayout(0)
3967 , m_strMachineName(strMachineName)
3968 , m_pSplitter(0)
3969 , m_pSidePanelWidget(0)
3970 , m_pKeyboardWidget(0)
3971 , m_pLayoutEditor(0)
3972 , m_pLayoutSelector(0)
3973 , m_pSettingsWidget(0)
3974 , m_pStatusBarWidget(0)
3975 , m_iGeometrySaveTimerId(-1)
3976{
3977 setWindowTitle(QString("%1 - %2").arg(m_strMachineName).arg(tr("Soft Keyboard")));
3978 prepareObjects();
3979 prepareConnections();
3980
3981 if (m_pKeyboardWidget)
3982 {
3983 m_pKeyboardWidget->loadLayouts();
3984 if (m_pLayoutEditor)
3985 m_pLayoutEditor->setPhysicalLayoutList(m_pKeyboardWidget->physicalLayouts());
3986 }
3987
3988 loadSettings();
3989 configure();
3990 uiCommon().setHelpKeyword(this, "soft-keyb");
3991}
3992
3993bool UISoftKeyboard::shouldBeMaximized() const
3994{
3995 return gEDataManager->softKeyboardDialogShouldBeMaximized();
3996}
3997
3998void UISoftKeyboard::closeEvent(QCloseEvent *event)
3999{
4000 QStringList strNameList = m_pKeyboardWidget->unsavedLayoutsNameList();
4001 /* Show a warning dialog when there are not saved layouts: */
4002 if (m_pKeyboardWidget && !strNameList.empty())
4003 {
4004 QString strJoinedString = strNameList.join("<br/>");
4005 if (!msgCenter().questionBinary(this, MessageType_Warning,
4006 tr("<p>Following layouts are edited/copied but not saved:</p>%1"
4007 "<p>Closing this dialog will cause loosing the changes. Proceed?</p>").arg(strJoinedString),
4008 0 /* auto-confirm id */,
4009 "Ok", "Cancel"))
4010 {
4011 event->ignore();
4012 return;
4013 }
4014 }
4015 m_pMachine->releaseKeys();
4016 emit sigClose();
4017 event->ignore();
4018}
4019
4020bool UISoftKeyboard::event(QEvent *pEvent)
4021{
4022 if (pEvent->type() == QEvent::WindowDeactivate)
4023 {
4024 if (m_pKeyboardWidget)
4025 m_pKeyboardWidget->parentDialogDeactivated();
4026 }
4027 else if (pEvent->type() == QEvent::KeyPress)
4028 {
4029 QKeyEvent *pKeyEvent = dynamic_cast<QKeyEvent*>(pEvent);
4030 if (pKeyEvent)
4031 {
4032 if (QKeySequence(pKeyEvent->key()) == QKeySequence::HelpContents)
4033 sltHandleHelpRequest();
4034 }
4035 }
4036 else if (pEvent->type() == QEvent::Resize ||
4037 pEvent->type() == QEvent::Move)
4038 {
4039 if (m_iGeometrySaveTimerId != -1)
4040 killTimer(m_iGeometrySaveTimerId);
4041 m_iGeometrySaveTimerId = startTimer(300);
4042 }
4043 else if (pEvent->type() == QEvent::Timer)
4044 {
4045 QTimerEvent *pTimerEvent = static_cast<QTimerEvent*>(pEvent);
4046 if (pTimerEvent->timerId() == m_iGeometrySaveTimerId)
4047 {
4048 killTimer(m_iGeometrySaveTimerId);
4049 m_iGeometrySaveTimerId = -1;
4050 saveDialogGeometry();
4051 }
4052 }
4053
4054 return QMainWindowWithRestorableGeometry::event(pEvent);
4055}
4056
4057void UISoftKeyboard::sltLayoutSelectionChanged(const QUuid &layoutUid)
4058{
4059 if (!m_pKeyboardWidget)
4060 return;
4061 m_pKeyboardWidget->setCurrentLayout(layoutUid);
4062 if (m_pLayoutSelector && m_pKeyboardWidget->currentLayout())
4063 m_pLayoutSelector->setCurrentLayoutIsEditable(m_pKeyboardWidget->currentLayout()->editable());
4064}
4065
4066void UISoftKeyboard::sltCurentLayoutChanged()
4067{
4068 if (!m_pKeyboardWidget)
4069 return;
4070 UISoftKeyboardLayout *pCurrentLayout = m_pKeyboardWidget->currentLayout();
4071
4072 /* Update the status bar string: */
4073 if (!pCurrentLayout)
4074 return;
4075 updateStatusBarMessage(pCurrentLayout->nameString());
4076 saveCurrentLayout();
4077}
4078
4079void UISoftKeyboard::sltShowLayoutSelector()
4080{
4081 if (m_pSidePanelWidget && m_pLayoutSelector)
4082 m_pSidePanelWidget->setCurrentWidget(m_pLayoutSelector);
4083 if (m_pKeyboardWidget)
4084 m_pKeyboardWidget->toggleEditMode(false);
4085 if (m_pLayoutEditor)
4086 m_pLayoutEditor->setKey(0);
4087}
4088
4089void UISoftKeyboard::sltShowLayoutEditor()
4090{
4091 if (m_pSidePanelWidget && m_pLayoutEditor)
4092 {
4093 m_pLayoutEditor->setLayoutToEdit(m_pKeyboardWidget->currentLayout());
4094 m_pSidePanelWidget->setCurrentWidget(m_pLayoutEditor);
4095 }
4096 if (m_pKeyboardWidget)
4097 m_pKeyboardWidget->toggleEditMode(true);
4098}
4099
4100void UISoftKeyboard::sltKeyToEditChanged(UISoftKeyboardKey* pKey)
4101{
4102 if (m_pLayoutEditor)
4103 m_pLayoutEditor->setKey(pKey);
4104}
4105
4106void UISoftKeyboard::sltLayoutEdited()
4107{
4108 if (!m_pKeyboardWidget)
4109 return;
4110 m_pKeyboardWidget->update();
4111 updateLayoutSelectorList();
4112 UISoftKeyboardLayout *pCurrentLayout = m_pKeyboardWidget->currentLayout();
4113
4114 /* Update the status bar string: */
4115 QString strLayoutName = pCurrentLayout ? pCurrentLayout->name() : QString();
4116 updateStatusBarMessage(strLayoutName);
4117}
4118
4119void UISoftKeyboard::sltKeyCaptionsEdited(UISoftKeyboardKey* pKey)
4120{
4121 Q_UNUSED(pKey);
4122 if (m_pKeyboardWidget)
4123 m_pKeyboardWidget->update();
4124}
4125
4126void UISoftKeyboard::sltShowHideSidePanel()
4127{
4128 if (!m_pSidePanelWidget)
4129 return;
4130 m_pSidePanelWidget->setVisible(!m_pSidePanelWidget->isVisible());
4131
4132 if (m_pSidePanelWidget->isVisible() && m_pSettingsWidget->isVisible())
4133 m_pSettingsWidget->setVisible(false);
4134}
4135
4136void UISoftKeyboard::sltShowHideSettingsWidget()
4137{
4138 if (!m_pSettingsWidget)
4139 return;
4140 m_pSettingsWidget->setVisible(!m_pSettingsWidget->isVisible());
4141 if (m_pSidePanelWidget->isVisible() && m_pSettingsWidget->isVisible())
4142 m_pSidePanelWidget->setVisible(false);
4143}
4144
4145void UISoftKeyboard::sltHandleColorThemeListSelection(const QString &strColorThemeName)
4146{
4147 if (m_pKeyboardWidget)
4148 m_pKeyboardWidget->setColorThemeByName(strColorThemeName);
4149 saveSelectedColorThemeName();
4150}
4151
4152void UISoftKeyboard::sltHandleKeyboardWidgetColorThemeChange()
4153{
4154 for (int i = (int)KeyboardColorType_Background;
4155 i < (int)KeyboardColorType_Max; ++i)
4156 {
4157 KeyboardColorType enmType = (KeyboardColorType)i;
4158 m_pSettingsWidget->setColorSelectionButtonBackgroundAndTooltip(enmType,
4159 m_pKeyboardWidget->color(enmType),
4160 m_pKeyboardWidget->isColorThemeEditable());
4161 }
4162}
4163
4164void UISoftKeyboard::sltCopyLayout()
4165{
4166 if (!m_pKeyboardWidget)
4167 return;
4168 m_pKeyboardWidget->copyCurentLayout();
4169 updateLayoutSelectorList();
4170}
4171
4172void UISoftKeyboard::sltSaveLayout()
4173{
4174 if (m_pKeyboardWidget)
4175 m_pKeyboardWidget->saveCurentLayoutToFile();
4176}
4177
4178void UISoftKeyboard::sltDeleteLayout()
4179{
4180 if (m_pKeyboardWidget)
4181 m_pKeyboardWidget->deleteCurrentLayout();
4182 updateLayoutSelectorList();
4183 if (m_pKeyboardWidget && m_pKeyboardWidget->currentLayout() && m_pLayoutSelector)
4184 {
4185 m_pLayoutSelector->setCurrentLayout(m_pKeyboardWidget->currentLayout()->uid());
4186 m_pLayoutSelector->setCurrentLayoutIsEditable(m_pKeyboardWidget->currentLayout()->editable());
4187 }
4188}
4189
4190void UISoftKeyboard::sltStatusBarMessage(const QString &strMessage)
4191{
4192 statusBar()->showMessage(strMessage, iMessageTimeout);
4193}
4194
4195void UISoftKeyboard::sltShowHideOSMenuKeys(bool fHide)
4196{
4197 if (m_pKeyboardWidget)
4198 m_pKeyboardWidget->setHideOSMenuKeys(fHide);
4199}
4200
4201void UISoftKeyboard::sltShowHideNumPad(bool fHide)
4202{
4203 if (m_pKeyboardWidget)
4204 m_pKeyboardWidget->setHideNumPad(fHide);
4205}
4206
4207void UISoftKeyboard::sltShowHideMultimediaKeys(bool fHide)
4208{
4209 if (m_pKeyboardWidget)
4210 m_pKeyboardWidget->setHideMultimediaKeys(fHide);
4211}
4212
4213void UISoftKeyboard::sltHandleColorCellClick(int iColorRow)
4214{
4215 if (!m_pKeyboardWidget || iColorRow >= static_cast<int>(KeyboardColorType_Max))
4216 return;
4217
4218 if (!m_pKeyboardWidget->isColorThemeEditable())
4219 return;
4220 const QColor &currentColor = m_pKeyboardWidget->color(static_cast<KeyboardColorType>(iColorRow));
4221 QColorDialog colorDialog(currentColor, this);
4222
4223 if (colorDialog.exec() == QDialog::Rejected)
4224 return;
4225 QColor newColor = colorDialog.selectedColor();
4226 if (currentColor == newColor)
4227 return;
4228 m_pKeyboardWidget->setColor(static_cast<KeyboardColorType>(iColorRow), newColor);
4229 m_pSettingsWidget->setColorSelectionButtonBackgroundAndTooltip(static_cast<KeyboardColorType>(iColorRow),
4230 newColor, m_pKeyboardWidget->isColorThemeEditable());
4231 saveCustomColorTheme();
4232}
4233
4234void UISoftKeyboard::sltResetKeyboard()
4235{
4236 if (m_pKeyboardWidget)
4237 m_pKeyboardWidget->reset();
4238 if (m_pLayoutEditor)
4239 m_pLayoutEditor->reset();
4240 m_pMachine->releaseKeys();
4241 update();
4242}
4243
4244void UISoftKeyboard::sltHandleHelpRequest()
4245{
4246 UIHelpBrowserDialog::findManualFileAndShow(uiCommon().helpKeyword(this));
4247}
4248
4249void UISoftKeyboard::prepareObjects()
4250{
4251 m_pSplitter = new QSplitter;
4252 if (!m_pSplitter)
4253 return;
4254 setCentralWidget(m_pSplitter);
4255 m_pSidePanelWidget = new QStackedWidget;
4256 if (!m_pSidePanelWidget)
4257 return;
4258
4259 m_pSidePanelWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
4260 m_pSidePanelWidget->hide();
4261
4262 m_pLayoutSelector = new UILayoutSelector;
4263 if (m_pLayoutSelector)
4264 m_pSidePanelWidget->addWidget(m_pLayoutSelector);
4265
4266 m_pLayoutEditor = new UIKeyboardLayoutEditor;
4267 if (m_pLayoutEditor)
4268 m_pSidePanelWidget->addWidget(m_pLayoutEditor);
4269
4270 m_pSettingsWidget = new UISoftKeyboardSettingsWidget;
4271 if (m_pSettingsWidget)
4272 {
4273 m_pSettingsWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
4274 m_pSettingsWidget->hide();
4275 }
4276 m_pKeyboardWidget = new UISoftKeyboardWidget(this, m_pMachine);
4277 if (!m_pKeyboardWidget)
4278 return;
4279 m_pKeyboardWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
4280 m_pKeyboardWidget->updateGeometry();
4281 m_pSplitter->addWidget(m_pKeyboardWidget);
4282 m_pSplitter->addWidget(m_pSidePanelWidget);
4283 m_pSplitter->addWidget(m_pSettingsWidget);
4284
4285 m_pSplitter->setCollapsible(0, false);
4286 m_pSplitter->setCollapsible(1, false);
4287 m_pSplitter->setCollapsible(2, false);
4288
4289 statusBar()->setStyleSheet( "QStatusBar::item { border: 0px}" );
4290 m_pStatusBarWidget = new UISoftKeyboardStatusBarWidget;
4291 statusBar()->addPermanentWidget(m_pStatusBarWidget);
4292}
4293
4294void UISoftKeyboard::prepareConnections()
4295{
4296 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigCurrentLayoutChange, this, &UISoftKeyboard::sltCurentLayoutChanged);
4297 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigKeyToEdit, this, &UISoftKeyboard::sltKeyToEditChanged);
4298 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigStatusBarMessage, this, &UISoftKeyboard::sltStatusBarMessage);
4299 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigCurrentColorThemeChanged, this, &UISoftKeyboard::sltHandleKeyboardWidgetColorThemeChange);
4300 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigOptionsChanged, this, &UISoftKeyboard::sltSaveSettings);
4301
4302 connect(m_pLayoutSelector, &UILayoutSelector::sigLayoutSelectionChanged, this, &UISoftKeyboard::sltLayoutSelectionChanged);
4303 connect(m_pLayoutSelector, &UILayoutSelector::sigShowLayoutEditor, this, &UISoftKeyboard::sltShowLayoutEditor);
4304 connect(m_pLayoutSelector, &UILayoutSelector::sigCloseLayoutList, this, &UISoftKeyboard::sltShowHideSidePanel);
4305 connect(m_pLayoutSelector, &UILayoutSelector::sigSaveLayout, this, &UISoftKeyboard::sltSaveLayout);
4306 connect(m_pLayoutSelector, &UILayoutSelector::sigDeleteLayout, this, &UISoftKeyboard::sltDeleteLayout);
4307 connect(m_pLayoutSelector, &UILayoutSelector::sigCopyLayout, this, &UISoftKeyboard::sltCopyLayout);
4308 connect(m_pLayoutEditor, &UIKeyboardLayoutEditor::sigGoBackButton, this, &UISoftKeyboard::sltShowLayoutSelector);
4309 connect(m_pLayoutEditor, &UIKeyboardLayoutEditor::sigLayoutEdited, this, &UISoftKeyboard::sltLayoutEdited);
4310 connect(m_pLayoutEditor, &UIKeyboardLayoutEditor::sigUIKeyCaptionsEdited, this, &UISoftKeyboard::sltKeyCaptionsEdited);
4311
4312 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigShowHideSidePanel, this, &UISoftKeyboard::sltShowHideSidePanel);
4313 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigShowSettingWidget, this, &UISoftKeyboard::sltShowHideSettingsWidget);
4314 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigResetKeyboard, this, &UISoftKeyboard::sltResetKeyboard);
4315 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigHelpButtonPressed, this, &UISoftKeyboard::sltHandleHelpRequest);
4316
4317 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigHideOSMenuKeys, this, &UISoftKeyboard::sltShowHideOSMenuKeys);
4318 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigHideNumPad, this, &UISoftKeyboard::sltShowHideNumPad);
4319 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigHideMultimediaKeys, this, &UISoftKeyboard::sltShowHideMultimediaKeys);
4320 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigColorCellClicked, this, &UISoftKeyboard::sltHandleColorCellClick);
4321 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigCloseSettingsWidget, this, &UISoftKeyboard::sltShowHideSettingsWidget);
4322 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigColorThemeSelectionChanged, this, &UISoftKeyboard::sltHandleColorThemeListSelection);
4323
4324 connect(&uiCommon(), &UICommon::sigAskToCommitData, this, &UISoftKeyboard::sltReleaseKeys);
4325}
4326
4327void UISoftKeyboard::saveDialogGeometry()
4328{
4329 const QRect geo = currentGeometry();
4330 LogRel2(("GUI: UISoftKeyboard: Saving geometry as: Origin=%dx%d, Size=%dx%d\n",
4331 geo.x(), geo.y(), geo.width(), geo.height()));
4332 gEDataManager->setSoftKeyboardDialogGeometry(geo, isCurrentlyMaximized());
4333}
4334
4335void UISoftKeyboard::saveCustomColorTheme()
4336{
4337 if (!m_pKeyboardWidget)
4338 return;
4339 /* Save the changes to the 'Custom' color theme to extra data: */
4340 QStringList colors = m_pKeyboardWidget->colorsToStringList("Custom");
4341 colors.prepend("Custom");
4342 gEDataManager->setSoftKeyboardColorTheme(colors);
4343}
4344
4345void UISoftKeyboard::saveSelectedColorThemeName()
4346{
4347 if (!m_pKeyboardWidget)
4348 return;
4349 gEDataManager->setSoftKeyboardSelectedColorTheme(m_pKeyboardWidget->currentColorThemeName());
4350}
4351
4352void UISoftKeyboard::saveCurrentLayout()
4353{
4354 if (m_pKeyboardWidget && m_pKeyboardWidget->currentLayout())
4355 gEDataManager->setSoftKeyboardSelectedLayout(m_pKeyboardWidget->currentLayout()->uid());
4356}
4357
4358void UISoftKeyboard::sltSaveSettings()
4359{
4360 /* Save other settings: */
4361 if (m_pKeyboardWidget)
4362 {
4363 gEDataManager->setSoftKeyboardOptions(m_pKeyboardWidget->hideNumPad(),
4364 m_pKeyboardWidget->hideOSMenuKeys(),
4365 m_pKeyboardWidget->hideMultimediaKeys());
4366 }
4367}
4368
4369void UISoftKeyboard::sltReleaseKeys()
4370{
4371 m_pMachine->releaseKeys();
4372}
4373
4374void UISoftKeyboard::loadSettings()
4375{
4376 /* Invent default window geometry: */
4377 float fKeyboardAspectRatio = 1.0f;
4378 if (m_pKeyboardWidget)
4379 fKeyboardAspectRatio = m_pKeyboardWidget->layoutAspectRatio();
4380 const QRect availableGeo = gpDesktop->availableGeometry(this);
4381 const int iDefaultWidth = availableGeo.width() / 2;
4382 const int iDefaultHeight = iDefaultWidth * fKeyboardAspectRatio;
4383 QRect defaultGeo(0, 0, iDefaultWidth, iDefaultHeight);
4384
4385 /* Load geometry from extradata: */
4386 const QRect geo = gEDataManager->softKeyboardDialogGeometry(this, m_pCenterWidget, defaultGeo);
4387 LogRel2(("GUI: UISoftKeyboard: Restoring geometry to: Origin=%dx%d, Size=%dx%d\n",
4388 geo.x(), geo.y(), geo.width(), geo.height()));
4389 restoreGeometry(geo);
4390
4391 /* Load other settings: */
4392 if (m_pKeyboardWidget)
4393 {
4394 QStringList colorTheme = gEDataManager->softKeyboardColorTheme();
4395 if (!colorTheme.empty())
4396 {
4397 /* The fist item is the theme name and the rest are color codes: */
4398 QString strThemeName = colorTheme[0];
4399 colorTheme.removeFirst();
4400 m_pKeyboardWidget->colorsFromStringList(strThemeName, colorTheme);
4401 }
4402 m_pKeyboardWidget->setColorThemeByName(gEDataManager->softKeyboardSelectedColorTheme());
4403 m_pKeyboardWidget->setCurrentLayout(gEDataManager->softKeyboardSelectedLayout());
4404
4405 /* Load other options from exra data: */
4406 bool fHideNumPad = false;
4407 bool fHideOSMenuKeys = false;
4408 bool fHideMultimediaKeys = false;
4409 gEDataManager->softKeyboardOptions(fHideNumPad, fHideOSMenuKeys, fHideMultimediaKeys);
4410 m_pKeyboardWidget->setHideNumPad(fHideNumPad);
4411 m_pKeyboardWidget->setHideOSMenuKeys(fHideOSMenuKeys);
4412 m_pKeyboardWidget->setHideMultimediaKeys(fHideMultimediaKeys);
4413 }
4414}
4415
4416void UISoftKeyboard::configure()
4417{
4418#ifndef VBOX_WS_MAC
4419 /* Assign window icon: */
4420 setWindowIcon(UIIconPool::iconSetFull(":/soft_keyboard_32px.png", ":/soft_keyboard_16px.png"));
4421#endif
4422
4423 if (m_pKeyboardWidget && m_pSettingsWidget)
4424 {
4425 m_pSettingsWidget->setHideOSMenuKeys(m_pKeyboardWidget->hideOSMenuKeys());
4426 m_pSettingsWidget->setHideNumPad(m_pKeyboardWidget->hideNumPad());
4427 m_pSettingsWidget->setHideMultimediaKeys(m_pKeyboardWidget->hideMultimediaKeys());
4428
4429 m_pSettingsWidget->setColorThemeNames(m_pKeyboardWidget->colorThemeNames());
4430 m_pSettingsWidget->setCurrentColorThemeName(m_pKeyboardWidget->currentColorThemeName());
4431
4432 for (int i = (int)KeyboardColorType_Background;
4433 i < (int)KeyboardColorType_Max; ++i)
4434 {
4435 KeyboardColorType enmType = (KeyboardColorType)i;
4436 m_pSettingsWidget->setColorSelectionButtonBackgroundAndTooltip(enmType,
4437 m_pKeyboardWidget->color(enmType),
4438 m_pKeyboardWidget->isColorThemeEditable());
4439 }
4440 }
4441 updateLayoutSelectorList();
4442 if (m_pKeyboardWidget && m_pKeyboardWidget->currentLayout() && m_pLayoutSelector)
4443 {
4444 m_pLayoutSelector->setCurrentLayout(m_pKeyboardWidget->currentLayout()->uid());
4445 m_pLayoutSelector->setCurrentLayoutIsEditable(m_pKeyboardWidget->currentLayout()->editable());
4446 }
4447}
4448
4449void UISoftKeyboard::updateStatusBarMessage(const QString &strName)
4450{
4451 if (!m_pStatusBarWidget)
4452 return;
4453 QString strMessage;
4454 if (!strName.isEmpty())
4455 {
4456 strMessage += QString("%1: %2").arg(tr("Layout")).arg(strName);
4457 m_pStatusBarWidget->updateLayoutNameInStatusBar(strMessage);
4458 }
4459 else
4460 m_pStatusBarWidget->updateLayoutNameInStatusBar(QString());
4461}
4462
4463void UISoftKeyboard::updateLayoutSelectorList()
4464{
4465 if (!m_pKeyboardWidget || !m_pLayoutSelector)
4466 return;
4467 m_pLayoutSelector->setLayoutList(m_pKeyboardWidget->layoutNameList(), m_pKeyboardWidget->layoutUidList());
4468}
4469
4470#include "UISoftKeyboard.moc"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette