[
  {
    "path": ".gitignore",
    "content": "# C++ objects and libs\n\n*.slo\n*.lo\n*.o\n*.a\n*.la\n*.lai\n*.so\n*.dll\n*.dylib\n\n# Qt-es\n\n/.qmake.cache\n/.qmake.stash\n*.pro.user\n*.pro.user.*\n*.moc\nmoc_*.cpp\nqrc_*.cpp\nui_*.h\nMakefile*\n*-build-*\n\n# QtCreator\n\n*.autosave\n\n#QtCtreator Qml\n*.qmlproject.user\n*.qmlproject.user.*\n\n#custom\n/build\n"
  },
  {
    "path": "QQStars.pro",
    "content": "TEMPLATE = app\r\nTARGET = QQStars\r\n\r\nQT += widgets network webkit svg qml quick concurrent sql quick-private#widgets-private core-private gui-private\r\nQT += webkitwidgets\r\n\r\nlinux:LIBS += -lXext\r\n\r\nINCLUDEPATH += \\\r\n    src \\\r\n    src/qxtglobalshortcut \\\r\n    src/qqstars \\\r\n    src/mywidgets \\\r\n    src/utility\r\n\r\nSOURCES += src/main.cpp \\\r\n    src/utility/mynetworkaccessmanagerfactory.cpp \\\r\n    src/utility/utility.cpp \\\r\n    src/mywidgets/mywindow.cpp \\\r\n    src/qqstars/qqstars.cpp \\\r\n    src/mywidgets/systemtrayicon.cpp \\\r\n    src/mywidgets/mysvgview.cpp \\ \r\n    src/mywidgets/myimage.cpp \\\r\n    src/mywidgets/mymessagebox.cpp \\\r\n    src/utility/myhttprequest.cpp \\\r\n    src/qqstars/qqiteminfo.cpp \\\r\n    src/utility/downloadimage.cpp \\\r\n    src/utility/texteditplaygif.cpp\r\n\r\nRESOURCES += \\\r\n    images.qrc \\\r\n    other.qrc \\\r\n    faces.qrc \\\r\n    qml.qrc \\\r\n    style.qrc\r\n\r\n# Additional import path used to resolve QML modules in Qt Creator's code model\r\nQML_IMPORT_PATH =\r\n\r\n# Default rules for deployment.\r\ninclude(deployment.pri)\r\ninclude (src/qxtglobalshortcut/qxtglobalshortcut.pri)\r\n#include (qmlapplicationviewer.pri)\r\n#qtcAddDeployment()\r\nHEADERS += \\\r\n    src/utility/mynetworkaccessmanagerfactory.h \\\r\n    src/utility/utility.h \\\r\n    src/mywidgets/mywindow.h \\\r\n    src/qqstars/qqstars.h \\\r\n    src/mywidgets/systemtrayicon.h \\\r\n    src/mywidgets/mysvgview.h \\ \r\n    src/mywidgets/myimage.h \\\r\n    src/mywidgets/mymessagebox.h \\\r\n    src/utility/myhttprequest.h \\\r\n    src/qqstars/qqiteminfo.h \\\r\n    src/utility/downloadimage.h \\\r\n    src/utility/texteditplaygif.h\r\n\r\nOTHER_FILES += \\\r\n    qml/Utility/CodeInput.qml \\\r\n    qml/Utility/MyButton.qml \\\r\n    qml/Utility/MyMessageBox.qml \\\r\n    qml/Utility/MyTextArea.qml \\\r\n    qml/Utility/MyTextField.qml \\\r\n    qml/Utility/SystemTray.qml \\\r\n    qml/Api/api.js \\\r\n    qml/Api/QQApi.qml \\\r\n    qml/Login/KeyboardPage/SoftKeyboard.qml \\\r\n    qml/Login/KeyboardPage/SoftKeyboardButton.qml \\\r\n    qml/Login/main.qml \\\r\n    qml/Login/SettingPage.qml \\\r\n    qml/MainPanel/ChatWindow/qqshow.png \\\r\n    qml/MainPanel/ListPage/AllListPage.qml \\\r\n    qml/MainPanel/ListPage/FriendList.qml \\\r\n    qml/MainPanel/ListPage/GroupList.qml \\\r\n    qml/MainPanel/ListPage/RecentList.qml \\\r\n    qml/MainPanel/main.qml \\\r\n    qml/MainPanel/MainPanelPage.qml \\\r\n    qml/Utility/ComboBox/MyComboBox.qml \\\r\n    qml/Utility/ComboBox/MyComboBoxComponent.qml \\\r\n    qml/Login/MyLoginButton.qml \\\r\n    qml/Chat/ChatWindowCommand.qml \\\r\n    qml/Chat/MessageListComponent.qml \\\r\n    qml/Chat/qqshow.png \\\r\n    qml/Utility/KeyboardPage/SoftKeyboard.qml \\\r\n    qml/Utility/KeyboardPage/SoftKeyboardButton.qml \\\r\n    qml/Utility/MyRectangularGlow.qml \\\r\n    qml/Utility/MyWindow.qml \\\r\n    qml/Utility/MyScrollView.qml \\\r\n    qml/Login/LoginPanel/AccountList.qml \\\r\n    qml/Login/LoginPanel/LoginCheckBox.qml \\\r\n    qml/Login/LoginPanel/LoginInputArea.qml \\\r\n    qml/Login/LoginPanel/LoginPage.qml \\\r\n    qml/QQItemInfo/DiscuInfo.qml \\\r\n    qml/QQItemInfo/FriendInfo.qml \\\r\n    qml/QQItemInfo/GroupInfo.qml \\\r\n    qml/MainPanel/ListPage/DiscuList.qml \\\r\n    qml/MainPanel/ListPage/GroupAndDiscuPage.qml \\\r\n    style/menuStyle.css \\\r\n    style/messageBoxStyle.css \\\r\n    qml/Chat/FriendChatPage.qml \\\r\n    qml/Chat/GroupChatPage.qml \\\r\n    qml/Chat/DiscuChatPage.qml \\\r\n    qml/Chat/ChatPage.qml \\\r\n    qml/Utility/TrayMessageWindow.qml \\\r\n    qml/Login/textedit.html \\\r\n    qml/Utility/MyTextView.qml\r\n            \r\nFORMS +=\r\n"
  },
  {
    "path": "README.md",
    "content": "#### 接口都已失效，此程序不再更新。\n\nQQStars\n=======\n\n[![Powered by DartNode](https://dartnode.com/branding/DN-Open-Source-sm.png)](https://dartnode.com \"Powered by DartNode - Free VPS for Open Source\")\n\n<b>此开源代码使用GPL授权方式</b>\n\n\n基于webqq协议的qq客户端，qt开发，可跨平台（主要给linux用户用，windows用户肯定不稀罕了）\n\n开发环境windows 7，qt 5.3.2\n\n下载链接：http://pan.baidu.com/s/1ntwW5DZ 密码: eeir。\n其中<b>QQStars-20141215gitd665984-1.fc21.x86_64.rpm</b>和<b>QQStars-20141215gitd665984-1.fc21.src.rpm</b>\n为朋友<b>LunarShaddow</b>编译和打包，在此表示衷心的感谢。\n\n直接解压，windows下直接运行QQStars.exe。\nlinux下运行QQStars.sh，如果程序无法启动就给同目录的QQStars加可执行权限。如果还是无法启动就是用终端运行QQStars.sh看有什么错误提示\n\n在LInux下如果无法输入中文的话请看此博客：http://www.cnblogs.com/AfterTheRainOfStars/p/3768484.html#3022718\n\n![登录界面](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/login.jpg)\n![设置界面](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/设置界面.jpg)\n![主面板](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/mainWindow.jpg)\n![好友列表](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/好友列表.jpg)\n![群列表](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/群列表.jpg)\n![讨论组](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/讨论组列表.jpg)\n![最近联系人列表](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/最近联系人列表.jpg)\n![好友聊天](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/好友聊天页.jpg)\n![群聊天](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/群聊天页.jpg)\n![讨论组聊天](https://github.com/AfterTheRainOfStars/QQStars/blob/master/introduce/讨论组聊天页.jpg)\n"
  },
  {
    "path": "deployment.pri",
    "content": "android-no-sdk {\r\n    target.path = /data/user/qt\r\n    export(target.path)\r\n    INSTALLS += target\r\n} else:android {\r\n    x86 {\r\n        target.path = /libs/x86\r\n    } else: armeabi-v7a {\r\n        target.path = /libs/armeabi-v7a\r\n    } else {\r\n        target.path = /libs/armeabi\r\n    }\r\n    export(target.path)\r\n    INSTALLS += target\r\n} else:unix {\r\n    isEmpty(target.path) {\r\n        qnx {\r\n            target.path = /tmp/$${TARGET}/bin\r\n        } else {\r\n            target.path = /opt/$${TARGET}/bin\r\n        }\r\n        export(target.path)\r\n    }\r\n    INSTALLS += target\r\n}\r\n\r\nexport(INSTALLS)\r\n"
  },
  {
    "path": "faces.qrc",
    "content": "<RCC>\r\n    <qresource prefix=\"/\">\r\n        <file>faces/classic/0.gif</file>\r\n        <file>faces/classic/0.png</file>\r\n        <file>faces/classic/1.gif</file>\r\n        <file>faces/classic/1.png</file>\r\n        <file>faces/classic/2.gif</file>\r\n        <file>faces/classic/2.png</file>\r\n        <file>faces/classic/3.gif</file>\r\n        <file>faces/classic/3.png</file>\r\n        <file>faces/classic/4.gif</file>\r\n        <file>faces/classic/4.png</file>\r\n        <file>faces/classic/5.gif</file>\r\n        <file>faces/classic/5.png</file>\r\n        <file>faces/classic/6.gif</file>\r\n        <file>faces/classic/6.png</file>\r\n        <file>faces/classic/7.gif</file>\r\n        <file>faces/classic/7.png</file>\r\n        <file>faces/classic/8.gif</file>\r\n        <file>faces/classic/8.png</file>\r\n        <file>faces/classic/9.gif</file>\r\n        <file>faces/classic/9.png</file>\r\n        <file>faces/classic/10.gif</file>\r\n        <file>faces/classic/10.png</file>\r\n        <file>faces/classic/11.gif</file>\r\n        <file>faces/classic/11.png</file>\r\n        <file>faces/classic/12.gif</file>\r\n        <file>faces/classic/12.png</file>\r\n        <file>faces/classic/13.gif</file>\r\n        <file>faces/classic/13.png</file>\r\n        <file>faces/classic/14.gif</file>\r\n        <file>faces/classic/14.png</file>\r\n        <file>faces/classic/21.png</file>\r\n        <file>faces/classic/23.gif</file>\r\n        <file>faces/classic/23.png</file>\r\n        <file>faces/classic/25.png</file>\r\n        <file>faces/classic/26.gif</file>\r\n        <file>faces/classic/26.png</file>\r\n        <file>faces/classic/27.gif</file>\r\n        <file>faces/classic/27.png</file>\r\n        <file>faces/classic/29.gif</file>\r\n        <file>faces/classic/29.png</file>\r\n        <file>faces/classic/32.png</file>\r\n        <file>faces/classic/33.png</file>\r\n        <file>faces/classic/34.png</file>\r\n        <file>faces/classic/36.png</file>\r\n        <file>faces/classic/37.gif</file>\r\n        <file>faces/classic/37.png</file>\r\n        <file>faces/classic/38.gif</file>\r\n        <file>faces/classic/38.png</file>\r\n        <file>faces/classic/39.png</file>\r\n        <file>faces/classic/42.png</file>\r\n        <file>faces/classic/45.png</file>\r\n        <file>faces/classic/46.gif</file>\r\n        <file>faces/classic/46.png</file>\r\n        <file>faces/classic/47.gif</file>\r\n        <file>faces/classic/47.png</file>\r\n        <file>faces/classic/50.png</file>\r\n        <file>faces/classic/51.gif</file>\r\n        <file>faces/classic/51.png</file>\r\n        <file>faces/classic/53.gif</file>\r\n        <file>faces/classic/53.png</file>\r\n        <file>faces/classic/54.gif</file>\r\n        <file>faces/classic/54.png</file>\r\n        <file>faces/classic/55.gif</file>\r\n        <file>faces/classic/55.png</file>\r\n        <file>faces/classic/56.gif</file>\r\n        <file>faces/classic/56.png</file>\r\n        <file>faces/classic/57.gif</file>\r\n        <file>faces/classic/57.png</file>\r\n        <file>faces/classic/58.gif</file>\r\n        <file>faces/classic/58.png</file>\r\n        <file>faces/classic/59.png</file>\r\n        <file>faces/classic/62.gif</file>\r\n        <file>faces/classic/62.png</file>\r\n        <file>faces/classic/63.gif</file>\r\n        <file>faces/classic/63.png</file>\r\n        <file>faces/classic/64.png</file>\r\n        <file>faces/classic/71.gif</file>\r\n        <file>faces/classic/71.png</file>\r\n        <file>faces/classic/72.gif</file>\r\n        <file>faces/classic/72.png</file>\r\n        <file>faces/classic/73.gif</file>\r\n        <file>faces/classic/73.png</file>\r\n        <file>faces/classic/74.gif</file>\r\n        <file>faces/classic/74.png</file>\r\n        <file>faces/classic/75.gif</file>\r\n        <file>faces/classic/75.png</file>\r\n        <file>faces/classic/76.gif</file>\r\n        <file>faces/classic/76.png</file>\r\n        <file>faces/classic/77.gif</file>\r\n        <file>faces/classic/77.png</file>\r\n        <file>faces/classic/78.gif</file>\r\n        <file>faces/classic/78.png</file>\r\n        <file>faces/classic/79.gif</file>\r\n        <file>faces/classic/79.png</file>\r\n        <file>faces/classic/80.gif</file>\r\n        <file>faces/classic/80.png</file>\r\n        <file>faces/classic/81.gif</file>\r\n        <file>faces/classic/81.png</file>\r\n        <file>faces/classic/82.gif</file>\r\n        <file>faces/classic/82.png</file>\r\n        <file>faces/classic/83.gif</file>\r\n        <file>faces/classic/83.png</file>\r\n        <file>faces/classic/84.gif</file>\r\n        <file>faces/classic/84.png</file>\r\n        <file>faces/classic/85.png</file>\r\n        <file>faces/classic/86.png</file>\r\n        <file>faces/classic/87.gif</file>\r\n        <file>faces/classic/87.png</file>\r\n        <file>faces/classic/88.gif</file>\r\n        <file>faces/classic/88.png</file>\r\n        <file>faces/classic/91.png</file>\r\n        <file>faces/classic/93.gif</file>\r\n        <file>faces/classic/93.png</file>\r\n        <file>faces/classic/95.gif</file>\r\n        <file>faces/classic/95.png</file>\r\n        <file>faces/classic/96.gif</file>\r\n        <file>faces/classic/96.png</file>\r\n        <file>faces/classic/97.gif</file>\r\n        <file>faces/classic/97.png</file>\r\n        <file>faces/classic/98.gif</file>\r\n        <file>faces/classic/98.png</file>\r\n        <file>faces/classic/99.gif</file>\r\n        <file>faces/classic/99.png</file>\r\n        <file>faces/classic/100.gif</file>\r\n        <file>faces/classic/100.png</file>\r\n        <file>faces/classic/101.gif</file>\r\n        <file>faces/classic/101.png</file>\r\n        <file>faces/classic/102.gif</file>\r\n        <file>faces/classic/102.png</file>\r\n        <file>faces/classic/103.gif</file>\r\n        <file>faces/classic/103.png</file>\r\n        <file>faces/classic/104.gif</file>\r\n        <file>faces/classic/104.png</file>\r\n        <file>faces/classic/105.gif</file>\r\n        <file>faces/classic/105.png</file>\r\n        <file>faces/classic/106.gif</file>\r\n        <file>faces/classic/106.png</file>\r\n        <file>faces/classic/107.gif</file>\r\n        <file>faces/classic/107.png</file>\r\n        <file>faces/classic/108.gif</file>\r\n        <file>faces/classic/108.png</file>\r\n        <file>faces/classic/109.gif</file>\r\n        <file>faces/classic/109.png</file>\r\n        <file>faces/classic/110.gif</file>\r\n        <file>faces/classic/110.png</file>\r\n        <file>faces/classic/111.gif</file>\r\n        <file>faces/classic/111.png</file>\r\n        <file>faces/classic/112.gif</file>\r\n        <file>faces/classic/112.png</file>\r\n        <file>faces/classic/113.gif</file>\r\n        <file>faces/classic/113.png</file>\r\n        <file>faces/classic/114.gif</file>\r\n        <file>faces/classic/114.png</file>\r\n        <file>faces/classic/115.gif</file>\r\n        <file>faces/classic/115.png</file>\r\n        <file>faces/classic/116.gif</file>\r\n        <file>faces/classic/116.png</file>\r\n        <file>faces/classic/117.gif</file>\r\n        <file>faces/classic/117.png</file>\r\n        <file>faces/classic/118.gif</file>\r\n        <file>faces/classic/118.png</file>\r\n        <file>faces/classic/119.gif</file>\r\n        <file>faces/classic/119.png</file>\r\n        <file>faces/classic/120.gif</file>\r\n        <file>faces/classic/120.png</file>\r\n        <file>faces/classic/121.gif</file>\r\n        <file>faces/classic/121.png</file>\r\n        <file>faces/classic/122.gif</file>\r\n        <file>faces/classic/122.png</file>\r\n        <file>faces/classic/123.gif</file>\r\n        <file>faces/classic/123.png</file>\r\n        <file>faces/classic/124.png</file>\r\n        <file>faces/classic/125.gif</file>\r\n        <file>faces/classic/125.png</file>\r\n        <file>faces/classic/126.gif</file>\r\n        <file>faces/classic/126.png</file>\r\n        <file>faces/classic/127.gif</file>\r\n        <file>faces/classic/127.png</file>\r\n        <file>faces/classic/128.gif</file>\r\n        <file>faces/classic/128.png</file>\r\n        <file>faces/classic/129.gif</file>\r\n        <file>faces/classic/129.png</file>\r\n        <file>faces/classic/130.gif</file>\r\n        <file>faces/classic/130.png</file>\r\n        <file>faces/classic/131.gif</file>\r\n        <file>faces/classic/131.png</file>\r\n        <file>faces/classic/132.gif</file>\r\n        <file>faces/classic/132.png</file>\r\n        <file>faces/classic/133.gif</file>\r\n        <file>faces/classic/133.png</file>\r\n        <file>faces/classic/134.gif</file>\r\n        <file>faces/classic/134.png</file>\r\n        <file>faces/classic/dfp.png</file>\r\n        <file>faces/classic/dfr.png</file>\r\n        <file>faces/classic/dhp.png</file>\r\n        <file>faces/classic/K歌.png</file>\r\n        <file>faces/classic/棒棒糖.png</file>\r\n        <file>faces/classic/爆筋.png</file>\r\n        <file>faces/classic/鞭炮.png</file>\r\n        <file>faces/classic/彩球.png</file>\r\n        <file>faces/classic/钞票.png</file>\r\n        <file>faces/classic/车厢.png</file>\r\n        <file>faces/classic/打伞.png</file>\r\n        <file>faces/classic/灯笼.png</file>\r\n        <file>faces/classic/灯泡.png</file>\r\n        <file>faces/classic/多云.png</file>\r\n        <file>faces/classic/发财.png</file>\r\n        <file>faces/classic/飞机.png</file>\r\n        <file>faces/classic/风车.png</file>\r\n        <file>faces/classic/高铁右车头.png</file>\r\n        <file>faces/classic/高铁左车头.png</file>\r\n        <file>faces/classic/购物.png</file>\r\n        <file>faces/classic/喝彩.png</file>\r\n        <file>faces/classic/喝奶.png</file>\r\n        <file>faces/classic/开车.png</file>\r\n        <file>faces/classic/闹钟.png</file>\r\n        <file>faces/classic/祈祷.png</file>\r\n        <file>faces/classic/青蛙.png</file>\r\n        <file>faces/classic/沙发.png</file>\r\n        <file>faces/classic/手枪.png</file>\r\n        <file>faces/classic/帅.png</file>\r\n        <file>faces/classic/双喜.png</file>\r\n        <file>faces/classic/下面.png</file>\r\n        <file>faces/classic/下雨.png</file>\r\n        <file>faces/classic/香蕉.png</file>\r\n        <file>faces/classic/熊猫.png</file>\r\n        <file>faces/classic/药.png</file>\r\n        <file>faces/classic/邮件.png</file>\r\n        <file>faces/classic/纸巾.png</file>\r\n        <file>faces/classic/钻戒.png</file>\r\n    </qresource>\r\n</RCC>\r\n"
  },
  {
    "path": "images.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/\">\n        <file>images/avatar.svg</file>\n        <file>images/avatar_left.png</file>\n        <file>images/avatar-border.svg</file>\n        <file>images/imaway.png</file>\n        <file>images/background_arabesquitic.svg</file>\n        <file>images/background_input.png</file>\n        <file>images/imbusy.png</file>\n        <file>images/button-login.svg</file>\n        <file>images/button-login-hover.svg</file>\n        <file>images/button-login-press.svg</file>\n        <file>images/button-minimize.svg</file>\n        <file>images/button-quit.svg</file>\n        <file>images/checkBox-hover.svg</file>\n        <file>images/imoffline.png</file>\n        <file>images/imonline.png</file>\n        <file>images/inputBox.svg</file>\n        <file>images/inputBox1.png</file>\n        <file>images/inputBox2.png</file>\n        <file>images/inputBox-close.svg</file>\n        <file>images/inputBox-more.svg</file>\n        <file>images/inputBox-password-clicked.svg</file>\n        <file>images/inputBox-password-hover.svg</file>\n        <file>images/inputBox-qq-clicked.svg</file>\n        <file>images/inputBox-qq-hover.svg</file>\n        <file>images/imhidden.png</file>\n        <file>images/list_arrow_down.png</file>\n        <file>images/list_arrow_up.png</file>\n        <file>images/list_item.png</file>\n        <file>images/list_item_bottom.png</file>\n        <file>images/lock20.png</file>\n        <file>images/login-panel.svg</file>\n        <file>images/login-panel-shadow.png</file>\n        <file>images/imsilent.png</file>\n        <file>images/progress-bar.png</file>\n        <file>images/imcallme.png</file>\n        <file>images/QQ-for-ubuntu.svg</file>\n        <file>images/soft-keyboard.svg</file>\n        <file>images/status-away-1.svg</file>\n        <file>images/status-busy-1.svg</file>\n        <file>images/status-callme-1.svg</file>\n        <file>images/status-hidden-1.svg</file>\n        <file>images/status-online-1.svg</file>\n        <file>images/status-silent-1.svg</file>\n        <file>images/unfold_icon.png</file>\n        <file>images/unlock20.png</file>\n        <file>images/checkBox-select.svg</file>\n        <file>images/checkBox-unselect.svg</file>\n        <file>images/bit.bmp</file>\n        <file>images/avatar.png</file>\n        <file>images/contact_press.png</file>\n        <file>images/group_press.png</file>\n        <file>images/TempSession_press.png</file>\n        <file>images/menu_background.png</file>\n        <file>images/button-settings.svg</file>\n        <file>images/inputBox1.svg</file>\n        <file>images/inputBox2.svg</file>\n        <file>images/bubble_放飞心情_left.png</file>\n        <file>images/bubble_放飞心情_right.png</file>\n        <file>images/bubble_经典_left.png</file>\n        <file>images/bubble_经典_right.png</file>\n        <file>images/bubble_祈福_left.png</file>\n        <file>images/bubble_祈福_right.png</file>\n        <file>images/bubble_微笑河马_left.png</file>\n        <file>images/bubble_微笑河马_right.png</file>\n        <file>images/friendList_select.svg</file>\n        <file>images/friendList_unselect.svg</file>\n        <file>images/groupList_select.svg</file>\n        <file>images/groupList_unselect.svg</file>\n        <file>images/recentList_select.svg</file>\n        <file>images/recentList_unselect.svg</file>\n        <file>images/未标题-1.png</file>\n        <file>images/star.png</file>\n        <file>images/greenStar.png</file>\n        <file>images/blueStar.png</file>\n        <file>images/login-panel2.svg</file>\n        <file>images/loading.png</file>\n        <file>images/dud.png</file>\n        <file>images/duz.png</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "other.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/\">\n        <file>qt_zh_CN.qm</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "qml/Api/QQApi.qml",
    "content": "import QtQuick 2.2\r\nimport utility 1.0\r\nimport QtQuick.Window 2.1\r\nimport QQItemInfo 1.0\r\nimport qqstars 1.0\r\n\r\nQQ{\r\n    id: root\r\n    property string re_uin: \"\"//用来存放测试qq是否需要验证码后返回的uin值（密码加密中需要用到）\r\n    property var loginReData//二次登陆后返回的数据(JSON格式)\r\n    property var userData//储存用户资料（JSON格式）\r\n    property var panelSize//存放主面板大小(网络数据)\r\n    property string clientid//存放网络强求需要的clientid\r\n    property var friendListData//储存好友列表\r\n    property string list_hash//获取好友列表时需要的hash\r\n    property string ptwebqq//登录后返回的cookie\r\n    property string psessionid: loginReData?loginReData.psessionid:\"\"//登录后返回的数据\r\n    property string vfwebqq: loginReData?loginReData.vfwebqq:\"\"//登录后返回的数据\r\n    \r\n    windowScale: {\r\n        var dosktopWidth = Screen.desktopAvailableWidth\r\n        if(dosktopWidth<=1366)\r\n            return 1\r\n        else if(dosktopWidth>1366&&dosktopWidth<=1600)\r\n            return 1.2\r\n        else if(dosktopWidth>1600&&dosktopWidth<=1920)\r\n            return 1.4\r\n        else if(dosktopWidth>1920&&dosktopWidth<=2300)\r\n            return 1.6\r\n        else if(dosktopWidth>2300&&dosktopWidth<=2600)\r\n            return 1.8\r\n        else if(dosktopWidth>2600)\r\n            return 2\r\n    }\r\n\r\n    onStateChanged: {\r\n        editUserState()//改变在线状态\r\n    }\r\n    \r\n    function random(min,max){\r\n        return Math.floor(min+Math.random()*(max-min));\r\n    }\r\n    function getClientid() {\r\n        return String(random(0, 99)) + String((new Date()).getTime() % 1000000)\r\n    }\r\n    \r\n    function showInputCodePage(callbackFun, uin) {\r\n        var component = Qt.createComponent(\"../Utility/CodeInput.qml\");\r\n        if (component.status == Component.Ready){\r\n            var url = \"https://ssl.captcha.qq.com/getimage?aid=1003903&r=0.9101365606766194&uin=\"+myqq.userQQ+\"&cap_cd=\"+uin\r\n            var data = {\"source\": url, \"backFun\":callbackFun};\r\n            var sprite = component.createObject(null, data);\r\n        }\r\n    }\r\n    \r\n    function login(code) {\r\n        if( myqq.loginStatus == QQ.Logining ){\r\n            if( code ) {//开始第一次登陆GET\r\n                var p = encryptionPassword(re_uin, code)\r\n                var url1 = \"https://ssl.ptlogin2.qq.com/login?u=\"+myqq.userQQ+\"&p=\"+p+\"&verifycode=\"+code+\"&webqq_type=10&remember_uin=1&login2qq=1&aid=1003903&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&h=1&ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=5-42-29419&mibao_css=m_webqq&t=1&g=1&js_type=0&js_ver=10087&login_sig=0RH3iE1ODTjmJJtKJ5MtDyoG*Q*pwgh2ABgmvw0E0zjdJpjPBbS*H9aZ4WRwLSFk&pt_uistyle=5\"\r\n                utility.httpGet(login1Finished, url1)\r\n            }else{//先检测qq号是否需要输入验证码\r\n                utility.socketAbort()//取消以前的网络请求\r\n                var url2 = \"https://ssl.ptlogin2.qq.com/check?uin=\"+myqq.userQQ+\"&appid=1003903&r=0.08757076971232891\"\r\n                utility.httpGet(testQQFinished, url2)\r\n            }\r\n        }\r\n    }\r\n    function testQQFinished(error, data) {//服务器返回qq是否需要验证码\r\n        if(error){//如果出错了\r\n            login()\r\n            return\r\n        }\r\n\r\n        if( myqq.loginStatus == QQ.Logining ){\r\n            var temp = data.split(\"'\")\r\n            re_uin = temp[5]//储存用来加密密码或获取验证码的uin\r\n            if( temp[1]==\"0\" ){\r\n                login(temp[3])//不需要验证码，直接登录\r\n            }else{\r\n                showCodeWindow(login, temp[3])//调用输入验证码，login为验证码获取成功后的回调函数\r\n            }\r\n        }\r\n    }\r\n    \r\n    function login1Finished(error, data){//登录之后服务器返回的数据\r\n        if(error){//如果出错了\r\n            login(myqq.codeText)//再次请求\r\n            return\r\n        }\r\n        if( myqq.loginStatus == QQ.Logining ){\r\n            var list = data.split (\"'\");\r\n            if( list[1]==0 ){\r\n                closeCodeWindow()//关闭输入验证码的窗口\r\n                var url = list[5]//先get一下返回数据中的url，来获取必要的Cookie\r\n                utility.httpGet(login2, url)//此地址GET完成后调用二次登录\r\n            }else{\r\n                myqq.showWarningInfo(\"登录失败：\"+list[9])\r\n                myqq.error(list[9])\r\n            }\r\n        }\r\n    }\r\n    \r\n    function login2() {\r\n        if( myqq.loginStatus == QQ.Logining ){\r\n            var url = \"http://d.web2.qq.com/channel/login2\"\r\n            ptwebqq = utility.getCookie(\"ptwebqq\")//储存cookie\r\n            list_hash = getHash()//储存hash\r\n            clientid = getClientid()//设置clientid\r\n            var data = 'r={\"status\":\"'+myqq.stateToString+'\",\"ptwebqq\":\"'+ptwebqq+'\",\"passwd_sig\":\"\",\"clientid\":\"'+clientid+'\",\"psessionid\":null}&clientid='+clientid+'&psessionid=null'\r\n            data = encodeURI(data)\r\n            utility.httpPost(login2Finished, url, data)\r\n        }\r\n    }\r\n    function reLogin(){//用于掉线后重新登录\r\n        var url = \"http://d.web2.qq.com/channel/login2\"\r\n        ptwebqq = utility.getCookie(\"ptwebqq\")//储存cookie\r\n        var data = 'r={\"status\":\"'+myqq.stateToString+'\",\"ptwebqq\":\"'+ptwebqq+'\",\"passwd_sig\":\"\",\"clientid\":\"'+clientid+'\",\"psessionid\":null}&clientid='+clientid+'&psessionid=null'\r\n        data = encodeURI(data)\r\n        utility.httpPost(reLoginFinished, url, data, true)\r\n    }\r\n    function reLoginFinished(error, data) {\r\n        if(error){\r\n            reLogin()\r\n            return\r\n        }\r\n        data = JSON.parse(data)\r\n        if( data.retcode==0 ) {\r\n            console.debug(\"重新登录完成\")\r\n            loginReData = data.result//将数据记录下来\r\n            var poll2data = 'r={\"clientid\":\"'+clientid+'\",\"psessionid\":\"'+psessionid+'\",\"key\":0,\"ids\":[]}&clientid='+clientid+'&psessionid='+psessionid\r\n            myqq.startPoll2(encodeURI(poll2data))//启动心跳包的post\r\n        }else{\r\n            console.debug(\"重新登录失败\")\r\n            showWarningInfo(\"QQ已掉线，请重新登录\")\r\n            root.loginStatus = QQ.WaitLogin//将登录状态设置为离线\r\n        }\r\n    }\r\n\r\n    function login2Finished(error, data) {//二次登录，这次才是真正的登录\r\n        if(error){//如果出错了\r\n            login2(null)\r\n            return\r\n        }\r\n        if( myqq.loginStatus == QQ.Logining ){\r\n            var list = JSON.parse(data)\r\n            if( list.retcode==0 ) {\r\n                loginReData = list.result//将数据记录下来\r\n                getUserData(myqq.userQQ, getDataFinished)//获取自己的资料\r\n                myqq.openSqlDatabase();//登录完成后，打开数据库(用来储存聊天记录)\r\n                myqq.loginStatus = QQ.LoginFinished//设置为登录成功\r\n                var poll2data = 'r={\"clientid\":\"'+clientid+'\",\"psessionid\":\"'+psessionid+'\",\"key\":0,\"ids\":[]}&clientid='+clientid+'&psessionid='+psessionid\r\n                myqq.startPoll2(encodeURI(poll2data))//启动心跳包的post\r\n                var url = \"http://q.qlogo.cn/headimg_dl?spec=240&dst_uin=\"+myqq.userQQ\r\n                downloadImage(QQItemInfo.Friend, url, myqq.userQQ, \"240\", getAvatarFinished)//获取头像\r\n            }else{\r\n                myqq.showWarningInfo(\"登陆出错，错误代码：\"+list.retcode)\r\n            }\r\n        }\r\n    }\r\n    \r\n    function getUserData(uin, backFun) {//获取用户资料，登录完成后的操作\r\n        var url = \"http://s.web2.qq.com/api/get_friend_info2?tuin=\"+uin+\"&verifysession=&code=&vfwebqq=\"+vfwebqq+\"&t=1407324674215\"\r\n        utility.httpGet(backFun, url, true)//第三个参数为true，是使用高优先级的网络请求\r\n    }\r\n    \r\n    function getDataFinished(error, data) {//获取用户资料成功后\r\n        if(error){//如果出错了\r\n            getUserData(myqq.userQQ, getDataFinished)//再次获取自己的资料\r\n            return\r\n        }\r\n        var list = JSON.parse(data)\r\n        if( list.retcode==0 ) {\r\n            userData = list.result\r\n            //console.debug(\"获取资料成功，我的昵称是：\"+userData.nick)\r\n            root.nick = String(userData.nick)//储存昵称\r\n            myqq.addLoginedQQInfo(userQQ, nick)//保存此账号的登录信息\r\n            //getPanelSize()//获取主面板的大小\r\n        }else{\r\n            getUserData(myqq.userQQ, getDataFinished)//再次获取自己的资料\r\n            //myqq.showWarningInfo(\"获取用户资料出错，错误代码：\"+list.retcode)\r\n        }\r\n    }\r\n    \r\n    function getPanelSize() {\r\n        if( myqq.loginStatus == QQ.Logining ){\r\n            //var url = \"http://cgi.web2.qq.com/keycgi/qqweb/newuac/get.do\"\r\n            //var data = 'r={\"appid\":50,\"itemlist\":[\"width\",\"height\",\"defaultMode\"]}&uin='+myqq.userQQ\r\n            //data = encodeURI(data)\r\n            //utility.httpPost(getPanelSizeFinished, url, data)\r\n            getPanelSizeFinished(false, \"\")\r\n        }\r\n    }\r\n    function getPanelSizeFinished ( error, data){\r\n        //var list = JSON.parse(data)\r\n        //if( list.retcode==0 ) {\r\n            //panelSize = list.result//保存获取的数据\r\n        //}else{\r\n            //utility.consoleLog(\"获取主面板大小出错，错误代码：\"+list.retcode)\r\n            panelSize = JSON.parse('{\"height\":500,\"defaultMode\":\"restore\",\"width\":240}')\r\n        //}\r\n        \r\n        /*var temp = myqq.value(\"rememberpassword\", 0)==1\r\n        console.log(\"是否保存密码：\"+temp)\r\n        if( temp ){//如果要保存密码\r\n            var pass = utility.stringEncrypt(myqq.userPassword, \"xingchenQQ\")//加密后储存\r\n            \r\n            //myqq.setValue(\"password\", pass)\r\n            console.log(\"保存的密码为：\"+myqq.value(\"password\", \"\"))\r\n        }*/\r\n       \r\n        //myqq.setValue( \"nick\", userData.nick)//保存昵称\r\n    }\r\n    function getQQSignature(uin, backFun){//获取好友个性签名 backFun为签名获取成功后调用\r\n        var url = \"http://s.web2.qq.com/api/get_single_long_nick2?tuin=\"+uin+\"&vfwebqq=\"+vfwebqq\r\n        utility.httpGet(backFun, url)\r\n    }\r\n    function getFriendList(backFun) {//获取好友列表\r\n        var url = \"http://s.web2.qq.com/api/get_user_friends2\"\r\n        var data = 'r={\"h\":\"hello\",\"hash\":\"'+getHash()+'\",\"vfwebqq\":\"'+vfwebqq+'\"}'\r\n        data = encodeURI(data)\r\n        utility.httpPost(backFun, url, data, true)\r\n    }\r\n    \r\n    function getGroupList(backFun) {//获取群列表\r\n        var url = \"http://s.web2.qq.com/api/get_group_name_list_mask2\"\r\n        var data = 'r={\"hash\":\"'+getHash()+'\",\"vfwebqq\":\"'+vfwebqq+'\"}'\r\n        data = encodeURI(data)\r\n        utility.httpPost(backFun, url, data, true)\r\n    }\r\n    \r\n    function getRecentList(backFun) {//获取最近联系人\r\n        var url = \"http://d.web2.qq.com/channel/get_recent_list2\"\r\n        var data = 'r={\"vfwebqq\":\"'+vfwebqq+'\",\"clientid\":\"'+clientid+'\",\"psessionid\":\"'+psessionid+'\"}&clientid='+clientid+'&psessionid='+psessionid\r\n        data = encodeURI(data)\r\n        utility.httpPost(backFun, url, data, true)\r\n    }\r\n    \r\n    function getDiscusList(backFun) {//讨论组列表\r\n        var url = \"http://s.web2.qq.com/api/get_discus_list?clientid=\"+clientid+\"&psessionid=\"+psessionid+\"&vfwebqq=\"+vfwebqq\r\n        utility.httpGet(backFun, url, true)\r\n    }\r\n    \r\n    function getFriendQQ( tuin, backFun ) {//获得好友真实的qq\r\n        var url = \"http://s.web2.qq.com/api/get_friend_uin2?tuin=\"+tuin+\"&verifysession=&type=1&code=&vfwebqq=\"+vfwebqq\r\n        utility.httpGet(backFun, url)\r\n    }\r\n    \r\n    function getAvatarFinished( error, path, name ){//获得自己头像完成\r\n        if(error==DownloadImage.DownloadError){//如果是下载出错\r\n            downloadImage(QQItemInfo.Friend, url, myqq.userQQ, \"240\", getAvatarFinished)//重新获取头像\r\n            return\r\n        }\r\n        if(error==DownloadImage.NoError)\r\n            myqq.avatar240 = path+\"/\"+name\r\n    }\r\n    \r\n    function getFriendInfo( tuin,backFun ) {//获取好友资料\r\n        var url = \"http://s.web2.qq.com/api/get_friend_info2?tuin=\"+tuin+\"&verifysession=&code=&vfwebqq=\"+vfwebqq\r\n        utility.httpGet(backFun, url)\r\n    }\r\n    \r\n    function editUserState(){\r\n        if( loginStatus == QQ.LoginFinished ) {\r\n            var url = \"http://d.web2.qq.com/channel/change_status2?newstatus=\"+myqq.stateToString+\"&clientid=\"+clientid+\"&psessionid=\"+psessionid\r\n            utility.httpGet(editUserStateFinished, url)\r\n        }\r\n    }\r\n    function editUserStateFinished(error, data){\r\n        if(error){\r\n            editUserState()//再次请求\r\n            return\r\n        }\r\n\r\n        data = JSON.parse(data)\r\n        if( data.retcode==0&&data.result==\"ok\" ){\r\n            console.log(\"状态改变成功\")\r\n            if(root.state==QQ.Offline){//如果状态变为离线\r\n                root.loginStatus = QQ.WaitLogin//改变登录状态\r\n            }\r\n        }\r\n    }\r\n    \r\n    function sendFriendMessage(backFun, uin, message){\r\n        while(message[message.length-1]==\"\\n\"){\r\n            message = message.substr(0, message.length-1)\r\n        }\r\n\r\n        var url = \"http://d.web2.qq.com/channel/send_buddy_msg2\"\r\n        var data = 'r={\"to\":'+uin+',\"face\":549,\"content\":\"[\\\\\"'+message+'\\\\\",\\\\\"\\\\\",[\\\\\"font\\\\\",{\\\\\"name\\\\\":\\\\\"宋体\\\\\",\\\\\"size\\\\\":\\\\\"10\\\\\",\\\\\"style\\\\\":[0,0,0],\\\\\"color\\\\\":\\\\\"000000\\\\\"}]]\",\"msg_id\":45070001,\"clientid\":\"'+clientid+'\",\"psessionid\":\"'+psessionid+'\"}&clientid='+clientid+'&psessionid='+psessionid\r\n        data = encodeURI(data)\r\n        utility.httpPost(backFun, url, data, true)\r\n    }\r\n    \r\n    function sendGroupMessage(backFun, uin, message){\r\n        while(message[message.length-1]==\"\\n\"){\r\n            message = message.substr(0, message.length-1)\r\n        }\r\n\r\n        var url = \"http://d.web2.qq.com/channel/send_qun_msg2\"\r\n        var data = 'r={\"group_uin\":'+uin+',\"content\":\"[\\\\\"'+message+'\\\\\",\\\\\"\\\\\",[\\\\\"font\\\\\",{\\\\\"name\\\\\":\\\\\"宋体\\\\\",\\\\\"size\\\\\":\\\\\"10\\\\\",\\\\\"style\\\\\":[0,0,0],\\\\\"color\\\\\":\\\\\"000000\\\\\"}]]\",\"msg_id\":29780002,\"clientid\":\"'+clientid+'\",\"psessionid\":\"'+psessionid+'\"}&clientid='+clientid+'&psessionid='+psessionid\r\n        data = encodeURI(data)\r\n        utility.httpPost(backFun, url, data, true)\r\n    }\r\n    \r\n    function sendDiscuMessage(backFun, uin, message){\r\n        while(message[message.length-1]==\"\\n\"){\r\n            message = message.substr(0, message.length-1)\r\n        }\r\n        \r\n        var url = \"http://d.web2.qq.com/channel/send_discu_msg2\"\r\n        var data = 'r={\"did\":'+uin+',\"content\":\"[\\\\\"'+message+'\\\\\",\\\\\"\\\\\",[\\\\\"font\\\\\",{\\\\\"name\\\\\":\\\\\"宋体\\\\\",\\\\\"size\\\\\":\\\\\"10\\\\\",\\\\\"style\\\\\":[0,0,0],\\\\\"color\\\\\":\\\\\"000000\\\\\"}]]\",\"msg_id\":29780002,\"clientid\":\"'+clientid+'\",\"psessionid\":\"'+psessionid+'\"}&clientid='+clientid+'&psessionid='+psessionid\r\n        data = encodeURI(data)\r\n        utility.httpPost(backFun, url, data, true)\r\n    }\r\n    function getGroupMembersList(callbackFun, gcode){//获取群成员列表\r\n        var url = \"http://s.web2.qq.com/api/get_group_info_ext2?gcode=\"+gcode+\"&cb=undefined&vfwebqq=\"+vfwebqq\r\n        utility.httpGet(callbackFun, url, true)\r\n    }\r\n    function getOnlineFriends(callbackFun){//获取在线好友列表\r\n        var url = \"http://d.web2.qq.com/channel/get_online_buddies2?clientid=\"+clientid+\"&psessionid=\"+psessionid\r\n        utility.httpGet(callbackFun, url, true)\r\n    }\r\n    function getDiscusMemberList(callbackFun, did) {//获取讨论组成员列表\r\n        var url = \"http://d.web2.qq.com/channel/get_discu_info?did=\"+did+\"&clientid=\"+clientid+\"&psessionid=\"+psessionid\r\n        utility.httpGet(callbackFun, url, true)\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Api/api.js",
    "content": "var hexcase = 1;\r\nvar b64pad = \"\";\r\nvar chrsz = 8;\r\nvar mode = 32;\r\nfunction md5(a) {\r\n    return hex_md5(a)\r\n}\r\nfunction hex_md5(a) {\r\n    return binl2hex(core_md5(str2binl(a), a.length * chrsz))\r\n}\r\nfunction str_md5(a) {\r\n    return binl2str(core_md5(str2binl(a), a.length * chrsz))\r\n}\r\nfunction hex_hmac_md5(a, b) {\r\n    return binl2hex(core_hmac_md5(a, b))\r\n}\r\nfunction b64_hmac_md5(a, b) {\r\n    return binl2b64(core_hmac_md5(a, b))\r\n}\r\nfunction str_hmac_md5(a, b) {\r\n    return binl2str(core_hmac_md5(a, b))\r\n}\r\nfunction core_md5(p, k) {\r\n    p[k >> 5] |= 128 << ((k) % 32);\r\n    p[(((k + 64) >>> 9) << 4) + 14] = k;\r\n    var o = 1732584193;\r\n    var n = -271733879;\r\n    var m = -1732584194;\r\n    var l = 271733878;\r\n    for (var g = 0; g < p.length; g += 16) {\r\n        var j = o;\r\n        var h = n;\r\n        var f = m;\r\n        var e = l;\r\n        o = md5_ff(o, n, m, l, p[g + 0], 7, -680876936);\r\n        l = md5_ff(l, o, n, m, p[g + 1], 12, -389564586);\r\n        m = md5_ff(m, l, o, n, p[g + 2], 17, 606105819);\r\n        n = md5_ff(n, m, l, o, p[g + 3], 22, -1044525330);\r\n        o = md5_ff(o, n, m, l, p[g + 4], 7, -176418897);\r\n        l = md5_ff(l, o, n, m, p[g + 5], 12, 1200080426);\r\n        m = md5_ff(m, l, o, n, p[g + 6], 17, -1473231341);\r\n        n = md5_ff(n, m, l, o, p[g + 7], 22, -45705983);\r\n        o = md5_ff(o, n, m, l, p[g + 8], 7, 1770035416);\r\n        l = md5_ff(l, o, n, m, p[g + 9], 12, -1958414417);\r\n        m = md5_ff(m, l, o, n, p[g + 10], 17, -42063);\r\n        n = md5_ff(n, m, l, o, p[g + 11], 22, -1990404162);\r\n        o = md5_ff(o, n, m, l, p[g + 12], 7, 1804603682);\r\n        l = md5_ff(l, o, n, m, p[g + 13], 12, -40341101);\r\n        m = md5_ff(m, l, o, n, p[g + 14], 17, -1502002290);\r\n        n = md5_ff(n, m, l, o, p[g + 15], 22, 1236535329);\r\n        o = md5_gg(o, n, m, l, p[g + 1], 5, -165796510);\r\n        l = md5_gg(l, o, n, m, p[g + 6], 9, -1069501632);\r\n        m = md5_gg(m, l, o, n, p[g + 11], 14, 643717713);\r\n        n = md5_gg(n, m, l, o, p[g + 0], 20, -373897302);\r\n        o = md5_gg(o, n, m, l, p[g + 5], 5, -701558691);\r\n        l = md5_gg(l, o, n, m, p[g + 10], 9, 38016083);\r\n        m = md5_gg(m, l, o, n, p[g + 15], 14, -660478335);\r\n        n = md5_gg(n, m, l, o, p[g + 4], 20, -405537848);\r\n        o = md5_gg(o, n, m, l, p[g + 9], 5, 568446438);\r\n        l = md5_gg(l, o, n, m, p[g + 14], 9, -1019803690);\r\n        m = md5_gg(m, l, o, n, p[g + 3], 14, -187363961);\r\n        n = md5_gg(n, m, l, o, p[g + 8], 20, 1163531501);\r\n        o = md5_gg(o, n, m, l, p[g + 13], 5, -1444681467);\r\n        l = md5_gg(l, o, n, m, p[g + 2], 9, -51403784);\r\n        m = md5_gg(m, l, o, n, p[g + 7], 14, 1735328473);\r\n        n = md5_gg(n, m, l, o, p[g + 12], 20, -1926607734);\r\n        o = md5_hh(o, n, m, l, p[g + 5], 4, -378558);\r\n        l = md5_hh(l, o, n, m, p[g + 8], 11, -2022574463);\r\n        m = md5_hh(m, l, o, n, p[g + 11], 16, 1839030562);\r\n        n = md5_hh(n, m, l, o, p[g + 14], 23, -35309556);\r\n        o = md5_hh(o, n, m, l, p[g + 1], 4, -1530992060);\r\n        l = md5_hh(l, o, n, m, p[g + 4], 11, 1272893353);\r\n        m = md5_hh(m, l, o, n, p[g + 7], 16, -155497632);\r\n        n = md5_hh(n, m, l, o, p[g + 10], 23, -1094730640);\r\n        o = md5_hh(o, n, m, l, p[g + 13], 4, 681279174);\r\n        l = md5_hh(l, o, n, m, p[g + 0], 11, -358537222);\r\n        m = md5_hh(m, l, o, n, p[g + 3], 16, -722521979);\r\n        n = md5_hh(n, m, l, o, p[g + 6], 23, 76029189);\r\n        o = md5_hh(o, n, m, l, p[g + 9], 4, -640364487);\r\n        l = md5_hh(l, o, n, m, p[g + 12], 11, -421815835);\r\n        m = md5_hh(m, l, o, n, p[g + 15], 16, 530742520);\r\n        n = md5_hh(n, m, l, o, p[g + 2], 23, -995338651);\r\n        o = md5_ii(o, n, m, l, p[g + 0], 6, -198630844);\r\n        l = md5_ii(l, o, n, m, p[g + 7], 10, 1126891415);\r\n        m = md5_ii(m, l, o, n, p[g + 14], 15, -1416354905);\r\n        n = md5_ii(n, m, l, o, p[g + 5], 21, -57434055);\r\n        o = md5_ii(o, n, m, l, p[g + 12], 6, 1700485571);\r\n        l = md5_ii(l, o, n, m, p[g + 3], 10, -1894986606);\r\n        m = md5_ii(m, l, o, n, p[g + 10], 15, -1051523);\r\n        n = md5_ii(n, m, l, o, p[g + 1], 21, -2054922799);\r\n        o = md5_ii(o, n, m, l, p[g + 8], 6, 1873313359);\r\n        l = md5_ii(l, o, n, m, p[g + 15], 10, -30611744);\r\n        m = md5_ii(m, l, o, n, p[g + 6], 15, -1560198380);\r\n        n = md5_ii(n, m, l, o, p[g + 13], 21, 1309151649);\r\n        o = md5_ii(o, n, m, l, p[g + 4], 6, -145523070);\r\n        l = md5_ii(l, o, n, m, p[g + 11], 10, -1120210379);\r\n        m = md5_ii(m, l, o, n, p[g + 2], 15, 718787259);\r\n        n = md5_ii(n, m, l, o, p[g + 9], 21, -343485551);\r\n        o = safe_add(o, j);\r\n        n = safe_add(n, h);\r\n        m = safe_add(m, f);\r\n        l = safe_add(l, e)\r\n    }\r\n    if (mode == 16) {\r\n        return Array(n, m)\r\n    } else {\r\n        return Array(o, n, m, l)\r\n    }\r\n}\r\nfunction md5_cmn(h, e, d, c, g, f) {\r\n    return safe_add(bit_rol(safe_add(safe_add(e, h), safe_add(c, f)), g), d)\r\n}\r\nfunction md5_ff(g, f, k, j, e, i, h) {\r\n    return md5_cmn((f & k) | ((~f) & j), g, f, e, i, h)\r\n}\r\nfunction md5_gg(g, f, k, j, e, i, h) {\r\n    return md5_cmn((f & j) | (k & (~j)), g, f, e, i, h)\r\n}\r\nfunction md5_hh(g, f, k, j, e, i, h) {\r\n    return md5_cmn(f ^ k ^ j, g, f, e, i, h)\r\n}\r\nfunction md5_ii(g, f, k, j, e, i, h) {\r\n    return md5_cmn(k ^ (f | (~j)), g, f, e, i, h)\r\n}\r\nfunction core_hmac_md5(c, f) {\r\n    var e = str2binl(c);\r\n    if (e.length > 16) {\r\n        e = core_md5(e, c.length * chrsz)\r\n    }\r\n    var a = Array(16),\r\n    d = Array(16);\r\n    for (var b = 0; b < 16; b++) {\r\n        a[b] = e[b] ^ 909522486;\r\n        d[b] = e[b] ^ 1549556828\r\n    }\r\n    var g = core_md5(a.concat(str2binl(f)), 512 + f.length * chrsz);\r\n    return core_md5(d.concat(g), 512 + 128)\r\n}\r\nfunction safe_add(a, d) {\r\n    var c = (a & 65535) + (d & 65535);\r\n    var b = (a >> 16) + (d >> 16) + (c >> 16);\r\n    return (b << 16) | (c & 65535)\r\n}\r\nfunction bit_rol(a, b) {\r\n    return (a << b) | (a >>> (32 - b))\r\n}\r\nfunction str2binl(d) {\r\n    var c = Array();\r\n    var a = (1 << chrsz) - 1;\r\n    for (var b = 0; b < d.length * chrsz; b += chrsz) {\r\n        c[b >> 5] |= (d.charCodeAt(b / chrsz) & a) << (b % 32)\r\n    }\r\n    return c\r\n}\r\nfunction binl2str(c) {\r\n    var d = \"\";\r\n    var a = (1 << chrsz) - 1;\r\n    for (var b = 0; b < c.length * 32; b += chrsz) {\r\n        d += String.fromCharCode((c[b >> 5] >>> (b % 32)) & a)\r\n    }\r\n    return d\r\n}\r\nfunction binl2hex(c) {\r\n    var b = hexcase ? \"0123456789ABCDEF\": \"0123456789abcdef\";\r\n    var d = \"\";\r\n    for (var a = 0; a < c.length * 4; a++) {\r\n        d += b.charAt((c[a >> 2] >> ((a % 4) * 8 + 4)) & 15) + b.charAt((c[a >> 2] >> ((a % 4) * 8)) & 15)\r\n    }\r\n    return d\r\n}\r\nfunction binl2b64(d) {\r\n    var c = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\r\n    var f = \"\";\r\n    for (var b = 0; b < d.length * 4; b += 3) {\r\n        var e = (((d[b >> 2] >> 8 * (b % 4)) & 255) << 16) | (((d[b + 1 >> 2] >> 8 * ((b + 1) % 4)) & 255) << 8) | ((d[b + 2 >> 2] >> 8 * ((b + 2) % 4)) & 255);\r\n        for (var a = 0; a < 4; a++) {\r\n            if (b * 8 + a * 6 > d.length * 32) {\r\n                f += b64pad\r\n            } else {\r\n                f += c.charAt((e >> 6 * (3 - a)) & 63)\r\n            }\r\n        }\r\n    }\r\n    return f\r\n}\r\nfunction hexchar2bin(str) {\r\n    var arr = [];\r\n    for (var i = 0; i < str.length; i = i + 2) {\r\n        arr.push(\"\\\\x\" + str.substr(i, 2))\r\n    }\r\n    arr = arr.join(\"\");\r\n    eval(\"var temp = '\" + arr + \"'\");\r\n    return temp\r\n}\r\nfunction uin2hex(str) {\r\n    var maxLength = 16;\r\n    str = parseInt(str);\r\n    var hex = str.toString(16);\r\n    var len = hex.length;\r\n    for (var i = len; i < maxLength; i++) {\r\n        hex = \"0\" + hex\r\n    }\r\n    var arr = [];\r\n    for (var j = 0; j < maxLength; j += 2) {\r\n        arr.push(\"\\\\x\" + hex.substr(j, 2))\r\n    }\r\n    var result = arr.join(\"\");\r\n    eval('result=\"' + result + '\"');\r\n    return result\r\n}\r\nfunction hexToString( hex ) {\r\n    var temp = hex.split(\"\\\\x\")\r\n    hex = \"\"\r\n    for( var i=1;i<temp.length;++i ) {\r\n        hex += (\"%\"+temp[i])\r\n    }\r\n    return unescape(hex)\r\n}\r\n\r\nfunction encryptionPassword( password , uin ,code) {\r\n    var j = hexchar2bin(md5(password));\r\n    var h = md5(j + hexToString(uin));\r\n    var g = md5(h + code.toUpperCase());\r\n    return g;\r\n}\r\n\r\nfunction getHash(b, j) {//b为自己的uin（qq号），j为ptwebqq,获取地址http://web.qstatic.com/webqqpic/pubapps/0/50/eqq.all.js\r\n    for (var a = j + \"password error\",\r\n    i = \"\",\r\n    E = [];;) if (i.length <= a.length) {\r\n        if (i += b, i.length == a.length) break\r\n    } else {\r\n        i = i.slice(0, a.length);\r\n        break\r\n    }\r\n    for (var c = 0; c < i.length; c++) E[c] = i.charCodeAt(c) ^ a.charCodeAt(c);\r\n    a = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"A\", \"B\", \"C\", \"D\", \"E\", \"F\"];\r\n    i = \"\";\r\n    for (c = 0; c < E.length; c++) i += a[E[c] >> 4 & 15],\r\n    i += a[E[c] & 15];\r\n    return i;\r\n}\r\n"
  },
  {
    "path": "qml/Chat/ChatPage.qml",
    "content": "import QtQuick 2.2\r\nimport utility 1.0\r\nimport mywindow 1.0\r\nimport QQItemInfo 1.0\r\nimport \"../\"\r\nimport \"../Utility\"\r\n\r\nItem{\r\n    id: root\r\n    anchors.fill: parent\r\n    property string myuin\r\n    property int type//记录自己的类型（好友，群，讨论组）\r\n    signal sendClicked//点击发送按钮好调用此函数\r\n    property alias menuBar: menu_bar\r\n    property alias rightBar: right_bar\r\n    property alias inputBox: input\r\n    property alias listModel: mymodel\r\n    property QQItemInfo myinfo//用来储存自己的各种信息（用uin标识)\r\n    \r\n    onMyinfoChanged: {\r\n        if(myinfo){//从缓冲区中读取数据\r\n            var message_list = myinfo.getChatRecords()//获取内存中的所有聊天记录\r\n            for(var i=0;i<message_list.size();++i){\r\n                var messageInfo = message_list.at(i)//读取第i条消息\r\n                var data = {\r\n                    \"sender_info\":myqq.createFriendInfo(messageInfo.senderUin),//发送者的info\r\n                    \"to_uin\":\"\",//如果mode为right才需要此值(为发送给谁)\r\n                    \"mode\": messageInfo.senderUin==myqq.userQQ?\"right\":\"left\",//要判断发送者是不是自己（这条消息是发送的还是接收的）\r\n                    \"message_info\": messageInfo,//此消息的各种信息\r\n                    \"parent_info\": myinfo\r\n                }\r\n                listModel.append(data)\r\n            }\r\n            scroll_list.contentAtEnd()//将内容拉到最后\r\n        }\r\n    }\r\n\r\n    Connections{\r\n        target: myqq//记录自己各种信息的类对象\r\n        onNewMessage:{\r\n            if(fromUin==myuin&&type == myinfo.mytype){\r\n                var data = {\r\n                    \"sender_info\":myqq.createFriendInfo(info.senderUin),//发送者的info\r\n                    \"to_uin\": \"\",\r\n                    \"mode\": \"left\",//要判断发送者是不是自己（这条消息是发送的还是接收的）\r\n                    \"message_info\": info,//消息内容\r\n                    \"parent_info\": myinfo\r\n                }\r\n                var temp = scroll_list.isContentEnd()//记录是否应该讲聊天页面拉到最后\r\n                listModel.append(data)\r\n                if(temp){\r\n                    scroll_list.contentAtEnd()//将内容拉到最后\r\n                }\r\n            }\r\n        }\r\n    }\r\n    \r\n    MyShortcut{\r\n        target: input\r\n        shortcut: \"Ctrl+Return\"\r\n        onTrigger: {\r\n            input.insert(input.cursorPosition, \"<br>\")\r\n        }\r\n    }\r\n    MyShortcut{\r\n        target: input\r\n        shortcut: \"Ctrl+Enter\"\r\n        onTrigger: {\r\n            input.insert(input.cursorPosition, \"<br>\")\r\n        }\r\n    }\r\n    MyShortcut{\r\n        target: input\r\n        shortcut: \"Return\"\r\n        onTrigger: {\r\n            button_send.clicked()\r\n        }\r\n    }\r\n    MyShortcut{\r\n        target: input\r\n        shortcut: \"Enter\"\r\n        onTrigger: {\r\n            button_send.clicked()\r\n        }\r\n    }\r\n\r\n    Rectangle{\r\n        anchors.fill: parent\r\n        color: \"#eee\"\r\n        radius: 10\r\n        Item{\r\n            id: menu_bar\r\n            height: 30\r\n            anchors.left: parent.left\r\n            anchors.right: parent.right\r\n            anchors.top: parent.top\r\n        }\r\n        \r\n        Item{\r\n            id: right_bar\r\n            anchors.top: menu_bar.bottom\r\n            anchors.right: parent.right\r\n            anchors.bottom: parent.bottom\r\n            width: 180\r\n        }\r\n        \r\n        MyTextArea{\r\n            id: input\r\n            //font.pointSize: 12\r\n            //wrapMode: TextEdit.Wrap\r\n            anchors.bottom: button_send.top\r\n            anchors.left: parent.left\r\n            anchors.right: right_bar.left\r\n            anchors.margins: 10\r\n            height: 100\r\n        }\r\n        MyButton{\r\n            id: button_send\r\n            anchors.right: right_bar.left\r\n            anchors.bottom: parent.bottom\r\n            anchors.margins: 10\r\n            text: \"发送\"\r\n            property int image_index: 0\r\n            onClicked: {\r\n                inputBox.selectAll()//先选中全部\r\n                var messageInfo = myinfo.getChatMessageInfoById(myinfo.getMessageIndex())\r\n                //创建一个新的聊天储存聊天内容各种信息的对象（例如发送时间等等）\r\n                messageInfo.contentData = input.selectedText\r\n                messageInfo.senderUin = myqq.userQQ//发送者为当前登录的qq\r\n                var data = {\r\n                    \"sender_info\":myqq,//发送者是当前登录的用户qq\r\n                    \"to_uin\":myuin,//发送给当前聊天页的好友或群\r\n                    \"mode\": \"right\",\r\n                    \"message_info\": messageInfo,\r\n                    \"parent_info\": myinfo\r\n                }\r\n                listModel.append(data)\r\n                inputBox.text = \"\"\r\n                scroll_list.contentAtEnd()//将内容放到最后\r\n            }\r\n        }\r\n        \r\n\r\n        Rectangle{\r\n            anchors.top: menu_bar.bottom\r\n            anchors.right: right_bar.left\r\n            anchors.bottom: input.top\r\n            anchors.left: parent.left\r\n            anchors.margins: 10\r\n            radius: 5\r\n            color: \"#f5f5f5\"\r\n            border.width: 2\r\n            border.color: \"#ddd\"\r\n            \r\n            MyScrollView{\r\n                id: scroll_list\r\n                anchors.fill: parent\r\n                anchors.margins: 5\r\n                function contentAtEnd(){\r\n                    var flickableItem = scroll_list.flickableItem\r\n                    flickableItem.contentY = flickableItem.contentHeight-scroll_list.height+60\r\n                    //console.debug(flickableItem.contentY+\",\"+(flickableItem.contentHeight-scroll_list.height+60))\r\n                }\r\n                function isContentEnd(){\r\n                    var flickableItem = scroll_list.flickableItem\r\n                    //console.debug(flickableItem.contentY+\",\"+(flickableItem.contentHeight-scroll_list.height-5))\r\n                    return flickableItem.contentY > flickableItem.contentHeight-scroll_list.height-5\r\n                }\r\n\r\n                Item{\r\n                    height: list.contentHeight+10\r\n                    width: scroll_list.width-25\r\n                    x:5\r\n                    implicitHeight: height\r\n                    implicitWidth: width\r\n                    \r\n                    ListView{\r\n                        id: list\r\n                        anchors.fill: parent\r\n                        spacing: 10\r\n                        property int old_contentHeight: 0\r\n                        \r\n                        model: ListModel{\r\n                            id: mymodel\r\n                        }\r\n                        delegate: MessageListComponent{}\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Chat/ChatWindowCommand.qml",
    "content": "import QtQuick 2.2\r\nimport utility 1.0\r\nimport mywindow 1.0\r\nimport QQItemInfo 1.0\r\nimport \"../Utility\"\r\n\r\nMyWindow{\r\n    id: root\r\n    \r\n    property ChatPage currentShowPage//记录当前显示中的聊天页面\r\n    property int chatPageWidth: myqq.value(\"chatPageWidth\", 600)//获取聊天页面的width, 初始化为600，聊天也的width\r\n    \r\n    visible: true\r\n    minimumHeight: 500\r\n    minimumWidth: item_chatPage.minWidth+left_bar.width//设置最小宽度\r\n    width: left_bar.width+item_chatPage.width\r\n    noBorder: true//无边框的\r\n    removable: true//可移动的\r\n    fixedSize: false//固定大小的\r\n    dockableWindow: false//可停靠的\r\n    topHint: false//窗口保持在最前端\r\n    noNotifyIcon:false//隐藏任务栏图标\r\n    color: \"transparent\"\r\n    windowGlowItem.color: \"black\"//\"#f07000\"\r\n    windowIcon: currentShowPage?currentShowPage.myinfo.avatar40:\"qrc:/images/avatar.png\"\r\n    \r\n    setLeftBorder: function(arg){\r\n        if(left_bar.isOpen&&left_bar.setBarDefaultWidth(left_bar.defaultWidth+arg)){//如果窗口大小设置成功\r\n            root.mySetLeftBorder(arg)//设置窗口位置\r\n        }else if(!left_bar.isOpen){\r\n            if(item_chatPage.setPageWidth(chatPageWidth+arg)){\r\n                root.mySetLeftBorder(arg)\r\n            }\r\n        }\r\n    }\r\n    setRightBorder: function(arg){\r\n        if(item_chatPage.setPageWidth(chatPageWidth+arg)){\r\n            root.mySetRightBorder(arg)\r\n        }\r\n    }\r\n    onVisibleChanged: {\r\n        if(visible)\r\n            root.showFront()//显示到最屏幕最前端\r\n    }\r\n    \r\n    \r\n    function setCurrentShowPage(page){\r\n        //console.log(page+\",\"+currentShowPage)\r\n        if(currentShowPage!==page&&page){//判断是否page就是当前活动页面\r\n            page.myinfo.isActiveChatPage=true//将他信息中是否为活跃页面的属性设置为true\r\n            page.visible = true\r\n            if(currentShowPage){\r\n                currentShowPage.visible = false//先将旧的page设置为隐藏\r\n                currentShowPage.myinfo.isActiveChatPage=false//将他信息中是否为活跃页面的属性设置为false\r\n            }\r\n            currentShowPage = page//\r\n        }\r\n    }\r\n\r\n    Item{\r\n        id: item_chatPage\r\n        \r\n        property int maxWidth: 99999\r\n        property int minWidth: 500\r\n        \r\n        objectName: \"ChatWindowCommandItem\"\r\n        anchors.top: parent.top\r\n        anchors.bottom: parent.bottom\r\n        anchors.left: left_bar.right\r\n        width: chatPageWidth\r\n\r\n        function setPageWidth(arg){\r\n            if(arg<=maxWidth&&arg>=minWidth){\r\n                chatPageWidth = arg\r\n                return true\r\n            }else{\r\n                return false\r\n            }\r\n        }\r\n        \r\n        Rectangle{\r\n            anchors.left: parent.left\r\n            color: \"#eee\"\r\n            width: 10\r\n            height: width\r\n            visible: left_bar.width>0\r\n        }\r\n        Rectangle{\r\n            anchors.bottom: parent.bottom\r\n            anchors.left: parent.left\r\n            color: \"#eee\"\r\n            width: 10\r\n            height: width\r\n            visible: left_bar.width>0\r\n        }\r\n    }\r\n    Connections{\r\n        target: myqq\r\n        onAddChatPageToWindow:{\r\n            setCurrentShowPage(item)//设置当前显示的页面为item\r\n            left_bar.addItem(item)//增加左栏\r\n        }\r\n        onActiveChatPageChanged:{//如果活跃的Page改变为item\r\n            //console.log(item)\r\n            setCurrentShowPage(item)//设置当前显示的页面为item\r\n        }\r\n    }\r\n    \r\n    Rectangle{//用来管理当前聊天窗口内聊天页面的左栏\r\n        id:left_bar\r\n        \r\n        property bool isOpen: false//记录此栏是否处于打开状态\r\n        property int maxWidth:200\r\n        property int minWidth:70\r\n        property int defaultWidth: myqq.value(\"chatWindowLeftBarWidth\", 150)//获取上次储存的值\r\n        \r\n        anchors.top: parent.top\r\n        anchors.left: parent.left\r\n        anchors.bottom: parent.bottom\r\n        color:\"#ddd\"\r\n        radius:10\r\n        clip: true\r\n        \r\n        onDefaultWidthChanged: {\r\n            if(isOpen){//如果是打开状态\r\n                setBarWidth(defaultWidth)//如果默认宽度改变就设置此栏的当前width\r\n            }\r\n        }\r\n        onWidthChanged: {\r\n            root.width = width+chatPageWidth//设置窗口的大小\r\n        }\r\n\r\n        function openBar(){\r\n            console.debug(\"调用了打开侧栏：\"+isOpen)\r\n            if(!animation_width.running&&(!isOpen)){\r\n                isOpen = true\r\n                animation_width.to = defaultWidth\r\n                animation_width.start()//启动动画\r\n            }\r\n        }\r\n        \r\n        function hideBar(){\r\n            if(!animation_width.running&&isOpen){\r\n                isOpen = false\r\n                animation_width.to = 0\r\n                animation_width.start()//启动动画\r\n            }\r\n        }\r\n        \r\n        function setBarDefaultWidth(arg){//设置默认的width\r\n            if(arg<=maxWidth&&arg>=minWidth){\r\n                defaultWidth = arg\r\n                return true\r\n            }else{\r\n                return false\r\n            }\r\n        }\r\n\r\n        function addItem(item){\r\n            var data={\r\n                \"obj_item\": item\r\n            }\r\n            mymodel.append(data)//增加条目\r\n        }\r\n        function setBarWidth(arg){\r\n            if(arg<=maxWidth&&arg>=minWidth){\r\n                width = arg\r\n            }\r\n        }\r\n        NumberAnimation{//动画控件\r\n            id: animation_width\r\n            target: left_bar\r\n            running: false\r\n            duration: 300\r\n            property: \"width\"\r\n        }\r\n        Rectangle{\r\n            anchors.right: parent.right\r\n            color: left_bar.color\r\n            width: parent.radius\r\n            height: width\r\n            visible: parent.width>0\r\n        }\r\n        Rectangle{\r\n            anchors.bottom: parent.bottom\r\n            anchors.right: parent.right\r\n            color: left_bar.color\r\n            width: parent.radius\r\n            height: width\r\n            visible: parent.width>0\r\n        }\r\n\r\n        MyScrollView{\r\n            anchors.fill: parent\r\n            anchors.topMargin: image_quit_icon.height+15\r\n            Item{\r\n                height: mymodel.count*45+10\r\n                width: left_bar.width\r\n                implicitHeight: height\r\n                implicitWidth: width\r\n                ListView{\r\n                   id: list\r\n                   interactive: false\r\n                   anchors.fill: parent\r\n                   anchors.margins: 5\r\n\r\n                   model: ListModel{\r\n                       id:mymodel\r\n                       onCountChanged: {\r\n                           if(count <= 1){//如果没有了Item就让左栏的width为0\r\n                               left_bar.hideBar()//隐藏此栏\r\n                           }else if(count==2){\r\n                               left_bar.openBar()//打开此栏\r\n                           }\r\n                       }\r\n                   }\r\n                   spacing :10\r\n                   delegate: component\r\n                }\r\n            }\r\n        }\r\n        \r\n        Component{\r\n            id: component\r\n            Item{\r\n                id: item_root\r\n                width: parent.width\r\n                height: avatar.height\r\n                property ChatPage my: obj_item\r\n                Rectangle{\r\n                    id: rect_hover\r\n                    width: parent.width+10\r\n                    height: parent.height+10\r\n                    anchors.centerIn: parent\r\n                    color: root.currentShowPage==my?\"#f07000\":\"#eee\"\r\n                    radius: 5\r\n                    opacity: 0.8\r\n                    visible: item_mouse.hovered||root.currentShowPage==my\r\n                }\r\n\r\n                MouseArea{\r\n                    id: item_mouse\r\n                    anchors.fill: parent\r\n                    hoverEnabled: true\r\n                    property bool hovered\r\n                    onEntered: {\r\n                        hovered = true\r\n                    }\r\n                    onExited: {\r\n                        hovered = false\r\n                    }\r\n                    onClicked: {\r\n                        setCurrentShowPage(my)//将自己设置为活跃页面\r\n                    }\r\n                }\r\n                \r\n                MyImage{\r\n                    id: avatar\r\n                    x:10\r\n                    width:35\r\n                    height: 35\r\n                    sourceSize.width: width\r\n                    grayscale: {//头像是否显示为黑白\r\n                        if(my)\r\n                            return my.myinfo.state == FriendInfo.Offline\r\n                        return false\r\n                    }\r\n\r\n                    source: {\r\n                        if(my!==null)\r\n                            return my.myinfo.avatar40\r\n                        else\r\n                            return \"\"\r\n                    }\r\n\r\n                    maskSource: \"qrc:/images/bit.bmp\"\r\n                }\r\n                Text{\r\n                    id:text_nick\r\n                    anchors.verticalCenter: avatar.verticalCenter\r\n                    anchors.left: avatar.right\r\n                    anchors.leftMargin: 10\r\n                    //font.pointSize: 14\r\n                    text: my?my.myinfo.aliasOrNick:\"\"\r\n                }\r\n                Rectangle{\r\n                    width: image_close_page.width+16\r\n                    height: image_close_page.height+10\r\n                    anchors.centerIn: image_close_page\r\n                    color: \"#eee\"\r\n                    radius: 5\r\n                    opacity: 0.75\r\n                    visible: image_close_page.visible&&root.currentShowPage!=my\r\n                }\r\n                Rectangle{\r\n                    width: text_message_count.implicitWidth+10\r\n                    height: image_close_page.width\r\n                    anchors.right: rect_hover.right\r\n                    anchors.rightMargin: 5\r\n                    anchors.verticalCenter: parent.verticalCenter\r\n                    color: \"red\"\r\n                    radius: height\r\n                    visible: my?my.myinfo.unreadMessagesCount>0:false\r\n                    Text{\r\n                        id: text_message_count\r\n                        anchors.centerIn: parent\r\n                        text: my?my.myinfo.unreadMessagesCount:\"0\"//未读消息的个数\r\n                        color: \"white\"\r\n                        onTextChanged: {\r\n                            if(text == \"100\"){\r\n                                text = \"99+\"\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n                SvgView{\r\n                    id:image_close_page\r\n                    width: defaultSize.width*myqq.windowScale\r\n                    source: \"qrc:/images/button-quit.svg\"\r\n                    anchors.right: rect_hover.right\r\n                    anchors.rightMargin: 5\r\n                    anchors.verticalCenter: parent.verticalCenter\r\n                    visible: item_mouse.hovered\r\n                    MouseArea{\r\n                        anchors.fill: parent\r\n                        onClicked: {\r\n                            mymodel.remove(index)//移除自己\r\n                            myqq.removeChatPage(my.myuin, my.type)//移除聊天页面\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        MouseArea{//接收这栏右边的鼠标事件\r\n            cursorShape :enabled?Qt.SizeHorCursor:Qt.ArrowCursor\r\n            anchors.right: parent.right\r\n            anchors.verticalCenter: parent.verticalCenter\r\n            height: root.height\r\n            width: 2\r\n            property real pressedX: 0\r\n            property real pressedY: 0\r\n            onPressed: {\r\n                pressedX = mouseX\r\n            }\r\n            onPositionChanged: {\r\n                var num_temp = mouseX-pressedX\r\n                left_bar.setBarDefaultWidth(left_bar.defaultWidth+num_temp)//设置左栏的width\r\n            }\r\n        }\r\n    }\r\n    \r\n    SvgView{\r\n        id:image_quit_icon\r\n        width: defaultSize.width*myqq.windowScale\r\n        source: \"qrc:/images/button-quit.svg\"\r\n        anchors.left: parent.left\r\n        anchors.top: parent.top\r\n        anchors.margins: 10\r\n        MouseArea{\r\n            anchors.fill: parent\r\n            onClicked: {\r\n                root.close()//关闭窗口\r\n                mymodel.clear()//清除所有model\r\n            }\r\n        }\r\n    }\r\n    SvgView{\r\n        id:image_minimize_icon\r\n        width: defaultSize.width*myqq.windowScale\r\n        source: \"qrc:/images/button-minimize.svg\"\r\n        anchors.top: image_quit_icon.top\r\n        anchors.left: image_quit_icon.right\r\n        MouseArea{\r\n            anchors.fill: parent\r\n            onClicked: {\r\n                root.showMinimized()\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Chat/DiscuChatPage.qml",
    "content": "import QtQuick 2.2\r\nimport utility 1.0\r\nimport QQItemInfo 1.0\r\nimport mywindow 1.0\r\nimport \"../Utility\"\r\n\r\nChatPage{\r\n    id: root\r\n    myinfo: myuin!=\"\"?myqq.createDiscuInfo(myuin):null\r\n    \r\n    onMyinfoChanged: {\r\n        if(!myinfo)\r\n            return\r\n        \r\n        if(myinfo.membersCount>0){//如果成员列表已经存在就直接添加到list中\r\n            for(var i=0;i<myinfo.membersCount;++i){\r\n                mymodel.append({\"obj_info\": myinfo.getMemberInfoByIndex(i)})\r\n            }\r\n        }else if(myinfo.uin!=\"\"){//去获取群列表\r\n            myqq.getDiscusMemberList(getMembersListFinished, myinfo.uin)\r\n        }\r\n    }\r\n    \r\n    function getMembersListFinished(error, data){//获取群成员列表完成\r\n        if(error){\r\n            myqq.getDiscusMemberList(getMembersListFinished, myinfo.uin)//如果出错就再次获取\r\n            console.debug(\"获取讨论组成员列表出错：\"+data)\r\n            return\r\n        }\r\n        \r\n        data = JSON.parse(data)\r\n        if( data.retcode == 0 ){\r\n            var members = data.result.mem_info\r\n\r\n            for(var j in members){\r\n                //console.debug(members[j].uin+\",\"+members[j].nick)\r\n                var info = myqq.createFriendInfo(members[j].uin)\r\n                //console.debug(members[j].uin+\",\"+members[j].nick)\r\n                info.nick = members[j].nick//储存讨论组成员昵称\r\n                //console.debug(members[j].uin+\",\"+members[j].nick)\r\n                root.myinfo.addMember(info)//将讨论组成员添加进去\r\n                //console.debug(members[j].uin+\",\"+members[j].nick)\r\n            }\r\n            \r\n            members = data.result.mem_status\r\n            for( j in members ){//设置讨论组成员的在线状态\r\n                info = myqq.createFriendInfo(members[j].uin)\r\n                info.stateToString = members[j].status\r\n            }\r\n        }\r\n    }\r\n    \r\n    Rectangle{\r\n        parent: rightBar\r\n        anchors.fill: parent\r\n        anchors.margins: 10\r\n        anchors.leftMargin: 0\r\n        radius: 5\r\n        color: \"#f5f5f5\"\r\n        border.width: 2\r\n        border.color: \"#ddd\"\r\n        \r\n        MyScrollView{\r\n            id: scroll_list\r\n            anchors.fill: parent\r\n\r\n            Item{\r\n                height: list_member.contentHeight+10\r\n                width: scroll_list.width-25\r\n                x:5\r\n                implicitHeight: height\r\n                implicitWidth: width\r\n\r\n                ListView{\r\n                    id: list_member\r\n                    anchors.fill: parent\r\n                    \r\n                    model: ListModel{\r\n                        id: mymodel\r\n                    }\r\n                    delegate: Item{\r\n                        id: item_root\r\n                        property FriendInfo myinfo: obj_info\r\n                        \r\n                        height: 30\r\n                        width: parent.width\r\n                        MyImage{\r\n                            id: image_avatar\r\n                            width: 24\r\n                            height: 24\r\n                            sourceSize.width: width\r\n                            anchors.verticalCenter: parent.verticalCenter\r\n                            grayscale: item_root.myinfo.state==FriendInfo.Offline\r\n                            maskSource: \"qrc:/images/bit.bmp\"\r\n                            source: item_root.myinfo.avatar40\r\n                        }\r\n                        Text{\r\n                            anchors.verticalCenter: image_avatar.verticalCenter\r\n                            anchors.left: image_avatar.right\r\n                            anchors.leftMargin: 5\r\n                            anchors.right: parent.right\r\n                            elide:Text.ElideRight\r\n                            text: item_root.myinfo.aliasOrNick+\"(\"+item_root.myinfo.account+\")\"\r\n                        }\r\n                        MouseArea{\r\n                            anchors.fill: parent\r\n                            onDoubleClicked: {\r\n                                myqq.addChatPage(item_root.myinfo.uin, QQItemInfo.Friend)//双击开始聊天\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n                Connections{\r\n                    target: root.myinfo\r\n                    onMemberIncrease:{//增加item\r\n                        mymodel.append({\"obj_info\": info})\r\n                    }\r\n                    onMemberReduce:{//移除item\r\n                        mymodel.remove(index)\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Chat/FriendChatPage.qml",
    "content": "import QtQuick 2.2\r\nimport utility 1.0\r\nimport \"../QQItemInfo\"\r\n\r\nChatPage{\r\n    id: root\r\n    myinfo: myuin!=\"\"?myqq.createFriendInfo(myuin):null\r\n    rightBar.width: 0//设置右边栏宽度为0\r\n    \r\n    Connections{\r\n        target: myqq\r\n        onShakeWindow:{\r\n            if(fromUin==myuin){\r\n                console.log(\"窗口震动消息\")\r\n                myqq.shakeChatMainWindow(root)//抖动聊天窗口\r\n            }\r\n        }\r\n        onFriendInputNotify:{\r\n            if(fromUin==myuin){\r\n                console.log(\"正在输入消息\")\r\n                show_text.text = myinfo.aliasOrNick+\"正在输入\"\r\n            }\r\n        }\r\n    }\r\n    \r\n    Timer{\r\n        id: timer_show_text\r\n        interval: 2000\r\n        onTriggered: {\r\n            show_text.text = \"\"\r\n        }\r\n    }\r\n\r\n    Text{\r\n        id: show_text\r\n        parent: menuBar\r\n        anchors.right: parent.right\r\n        anchors.rightMargin: 10\r\n        verticalAlignment: Text.AlignVCenter\r\n        anchors.verticalCenter: parent.verticalCenter\r\n        onTextChanged: {\r\n            if(text!=\"\"){\r\n                timer_show_text.start()\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Chat/GroupChatPage.qml",
    "content": "import QtQuick 2.2\r\nimport utility 1.0\r\nimport mywindow 1.0\r\nimport QQItemInfo 1.0\r\nimport \"../Utility\"\r\n\r\nChatPage{\r\n    id: root\r\n    myinfo: myuin!=\"\"?myqq.createGroupInfo(myuin):null\r\n    \r\n    onMyinfoChanged: {\r\n        if(!myinfo)\r\n            return\r\n        \r\n        if(myinfo.membersCount>0){//如果成员列表已经存在就直接添加到list中\r\n            for(var i=0;i<myinfo.membersCount;++i){\r\n                mymodel.append({\"obj_info\": myinfo.getMemberInfoByIndex(i)})\r\n            }\r\n        }else if(myinfo.code!=\"\"){//去获取群列表\r\n            myqq.getGroupMembersList(getMembersListFinished, myinfo.code)\r\n        }\r\n    }\r\n    function getMembersListFinished(error, data){//获取群成员列表完成\r\n        if(error){\r\n            myqq.getGroupMembersList(getMembersListFinished, myinfo.code)//如果出错就再次获取\r\n            console.debug(\"获取群成员列表出错：\"+data)\r\n            return\r\n        }\r\n\r\n        data = JSON.parse(data)\r\n        if( data.retcode == 0 ){\r\n            myinfo.announcement = data.result.ginfo.memo//设置群公告\r\n            \r\n            var members = data.result.cards\r\n            for ( var i in members ){\r\n                root.myinfo.setMemberCard(members[i].muin, members[i].card)//储存群名片\r\n            }\r\n            \r\n            members = data.result.minfo\r\n            for(var j in members){\r\n                var info = myqq.createFriendInfo(members[j].uin)\r\n                info.nick = members[j].nick//储存群成员昵称\r\n                root.myinfo.addMember(info)//将群成员添加进去\r\n            }\r\n            \r\n            members = data.result.stats\r\n            for(j in members){//设置群成员的在线状态\r\n                info = myqq.createFriendInfo(members[j].uin)\r\n                switch(members[j].stat){\r\n                case 10://在线\r\n                    info.state = FriendInfo.Online\r\n                    break;\r\n                case 60://Q我吧\r\n                    info.state = FriendInfo.Callme\r\n                    break;\r\n                case 30://离开\r\n                    info.state = FriendInfo.Away\r\n                    break;\r\n                case 40://隐身\r\n                    info.state = FriendInfo.Hidden\r\n                    break;\r\n                case 50://忙碌\r\n                    info.state = FriendInfo.Busy\r\n                    break;\r\n                case 70://请勿打扰\r\n                    info.state = FriendInfo.Silent\r\n                    break;\r\n                default: break;\r\n                }\r\n            }\r\n        }\r\n    }\r\n    \r\n    Item{\r\n        parent: rightBar\r\n        anchors.fill: parent\r\n        \r\n        Rectangle{\r\n            id: group_announcement//群公告\r\n            anchors.top: parent.top\r\n            anchors.left: parent.left\r\n            anchors.right: parent.right\r\n            height: width\r\n            anchors.margins: 10\r\n            anchors.leftMargin: 0\r\n            radius: 5\r\n            color: \"#f5f5f5\"\r\n            border.width: 2\r\n            border.color: \"#ddd\"\r\n            \r\n            Text{\r\n                id: text_announcement\r\n                text: myinfo.announcement//群公告\r\n                anchors.fill: parent\r\n                anchors.margins: 10\r\n                wrapMode: Text.WordWrap\r\n                elide:Text.ElideRight\r\n            }\r\n        }\r\n        \r\n        Rectangle{\r\n            anchors.top: group_announcement.bottom\r\n            anchors.bottom: parent.bottom\r\n            anchors.left: parent.left\r\n            anchors.right: parent.right\r\n            anchors.margins: 10\r\n            anchors.leftMargin: 0\r\n            radius: 5\r\n            color: \"#f5f5f5\"\r\n            border.width: 2\r\n            border.color: \"#ddd\"\r\n            \r\n            MyScrollView{\r\n                id: scroll_list\r\n                anchors.fill: parent\r\n    \r\n                Item{\r\n                    height: mymodel.count*30+10\r\n                    width: scroll_list.width-25\r\n                    x:5\r\n                    implicitHeight: height\r\n                    implicitWidth: width\r\n\r\n                    ListView{\r\n                        id: list_member\r\n                        anchors.fill: parent\r\n                        \r\n                        model: ListModel{\r\n                            id: mymodel\r\n                        }\r\n                        delegate: Item{\r\n                            id: item_root\r\n                            property FriendInfo myinfo: obj_info\r\n                            \r\n                            height: 30\r\n                            width: parent.width\r\n                            MyImage{\r\n                                id: image_avatar\r\n                                width: 24\r\n                                height: 24\r\n                                sourceSize.width: width\r\n                                anchors.verticalCenter: parent.verticalCenter\r\n                                maskSource: \"qrc:/images/bit.bmp\"\r\n                                grayscale: item_root.myinfo.state==FriendInfo.Offline\r\n                                source: item_root.myinfo.avatar40\r\n                            }\r\n                            Text{\r\n                                anchors.verticalCenter: image_avatar.verticalCenter\r\n                                anchors.left: image_avatar.right\r\n                                anchors.leftMargin: 5\r\n                                anchors.right: parent.right\r\n                                elide:Text.ElideRight\r\n                                text: root.myinfo.getMemberCardByUin(\r\n                                          item_root.myinfo.uin, \r\n                                          item_root.myinfo.aliasOrNick)+\r\n                                      \"(\"+item_root.myinfo.account+\")\"\r\n                            }\r\n                            MouseArea{\r\n                                anchors.fill: parent\r\n                                onDoubleClicked: {\r\n                                    myqq.addChatPage(item_root.myinfo.uin, QQItemInfo.Friend)//双击开始聊天\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                    Connections{\r\n                        target: root.myinfo\r\n                        onMemberIncrease:{//增加item\r\n                            mymodel.append({\"obj_info\": info})\r\n                        }\r\n                        onMemberReduce:{//移除item\r\n                            mymodel.remove(index)\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Chat/MessageListComponent.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\nimport QQItemInfo 1.0\r\nimport MyTextEditPlugin 1.0\r\nimport \"../Utility\"\r\n\r\nComponent{\r\n    Item{\r\n        id: root\r\n        width: parent.width\r\n        height: nick.implicitHeight+backgound.height+backgound.anchors.topMargin\r\n        property FriendInfo myinfo: sender_info\r\n        //这条消息的发送者的信息，好友发送的话就是你的好友本身，群里边就是此条群消息的发送者\r\n        property QQItemInfo parentInfo: parent_info\r\n        //消息属主的info，好友里面就是你的好友本身，群里边就是群本身\r\n        property ChatMessageInfo messageInfo: message_info\r\n        //这条消息自身的信息，千万不要和parentInfo和myinfo搞混了\r\n        property string toUin: to_uin\r\n        \r\n        property var sendMessage: {\r\n            if(!parentInfo)\r\n                return null\r\n            switch(parentInfo.mytype){\r\n                case QQItemInfo.Friend:\r\n                    return myqq.sendFriendMessage\r\n                case QQItemInfo.Group:\r\n                    return myqq.sendGroupMessage\r\n                case QQItemInfo.Discu:\r\n                    return myqq.sendDiscuMessage\r\n                default:{\r\n                    return\r\n                }\r\n            }\r\n        }\r\n\r\n        Component.onCompleted: {\r\n            //console.log(message)//输出消息内容\r\n            if(sendMessage&&mode==\"right\"&&toUin!=\"\"){//如果为模式right代表是要发送消息\r\n                sendMessage(sendMessageFinished, toUin, messageInfo.contentData)//发送消息\r\n            }\r\n        }\r\n        function sendMessageFinished(error, data){//如果这个Item发送信息，此函数用来接收发送结果\r\n            //console.log(data)\r\n            if(!error){//如果没有出错\r\n                data = JSON.parse(data)\r\n                if(data.retcode==0&&data.result==\"ok\"){\r\n                    var date_time = new Date\r\n                    messageInfo.date = date_time.getDate()\r\n                    messageInfo.time = date_time.getTime()\r\n                    parentInfo.addChatRecord(messageInfo)//将聊天记录保存到内存当中\r\n                    console.debug(\"消息发送成功\")\r\n                }else{\r\n                    console.log(\"发送失败\")\r\n                    mytext.append('<font color=\"red\">[发送失败]</font>')\r\n                    messageInfo.destroy()//销毁此对象\r\n                }\r\n            }else{\r\n                console.log(\"发送失败\")\r\n                mytext.text+=\":发送失败\"\r\n            }\r\n        }\r\n        MyImage{\r\n            id: avatar\r\n            x:mode==\"left\"?0:root.width-width\r\n            width:40\r\n            height: 40\r\n            sourceSize.width: width\r\n            maskSource: \"qrc:/images/bit.bmp\"\r\n            source: root.myinfo.avatar40\r\n            onLoadError: {\r\n                avatar.source = \"qrc:/images/avatar.png\"\r\n            }\r\n        }\r\n        Text{\r\n            id: nick\r\n            x: mode==\"left\"?avatar.x+avatar.width+5:avatar.x-implicitWidth-5\r\n            anchors.top: avatar.top\r\n            text: root.myinfo.aliasOrNick\r\n        }\r\n\r\n        BorderImage {\r\n            id: backgound\r\n            x: mode==\"left\"?avatar.x+avatar.width+5:avatar.x-width-5\r\n            anchors.top: nick.bottom\r\n            anchors.topMargin: 5\r\n            source: \"qrc:/images/bubble_放飞心情_\"+mode+\".png\"\r\n            height: mytext.height+20\r\n            width: mytext.width+30\r\n            border.left: 20; border.top: 20\r\n            border.right: 20; border.bottom: 20\r\n           \r\n            \r\n            TextEdit{\r\n                id: mytext\r\n                anchors.centerIn: parent\r\n                readOnly: true\r\n                textFormat :TextEdit.RichText//支持富文本\r\n                selectByMouse :true\r\n                selectByKeyboard :true\r\n                wrapMode: TextEdit.Wrap\r\n                text: root.messageInfo.contentData\r\n                \r\n                onWidthChanged: {\r\n                    var temp = root.width-avatar.width-35\r\n                    if(width>temp){\r\n                        width = temp\r\n                    }\r\n                }\r\n                onTextChanged: {\r\n                    //console.debug(text)\r\n                    if(text[text.length-1]==\"\\n\"){\r\n                        text = text.substr(0, text.length-1)\r\n                    }\r\n                }\r\n                \r\n                TextEditPlayGif{\r\n                    target: mytext\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Login/LoginPanel/AccountList.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Window 2.1\r\nimport mywindow 1.0\r\nimport utility 1.0\r\n\r\nWindow{\r\n    id:root\r\n    height: list.contentHeight\r\n    flags: Qt.SplashScreen\r\n    color: \"transparent\"\r\n    visible: true\r\n    property bool isCanClose: false\r\n    signal listClose\r\n    signal clicked( var qq )\r\n    property int highlightIndex: 0//初始化为第0个\r\n    \r\n    Component{\r\n        id: component\r\n        Image{\r\n            id: background_iamge\r\n            source: index == mymodel.count-1?\"qrc:/images/list_item_bottom.png\":\"qrc:/images/list_item.png\"\r\n            width: root.width\r\n            height: {\r\n                if(root.highlightIndex == index)\r\n                    return 5/21*width\r\n                else\r\n                    return Math.max(5/21*width-10*Math.max(root.highlightIndex-index, index-root.highlightIndex), 4/21*width)\r\n            }\r\n            property bool is: false\r\n            Behavior on height{\r\n                NumberAnimation{\r\n                    duration: 200\r\n                }\r\n            }\r\n            \r\n            Rectangle{\r\n                id: background_rect\r\n                anchors.top: parent.top\r\n                anchors.topMargin: 1\r\n                x:2\r\n                width: parent.width-4\r\n                anchors.bottom: parent.bottom\r\n                anchors.bottomMargin: index == mymodel.count-1?2:1\r\n                color: root.highlightIndex == index?\"#fd7000\":\"#F3F2F2\"\r\n            }\r\n\r\n            MyImage{\r\n                id: image\r\n                maskSource: \"qrc:/images/bit.bmp\"\r\n                source: mysource\r\n                x:5\r\n                width: parent.height-10\r\n                height: width\r\n                sourceSize.width: width\r\n                anchors.verticalCenter: parent.verticalCenter\r\n                onLoadError: {\r\n                    source = \"qrc:/images/avatar.png\"\r\n                }\r\n            }\r\n            Text{\r\n                id:text\r\n                font.pointSize: parent.height/6\r\n                anchors.left: image.right\r\n                anchors.leftMargin: 10\r\n                anchors.verticalCenter: parent.verticalCenter\r\n                text: root.highlightIndex==index?\"<font color=\\\"black\\\">\"+nick+\"</font>\"+\"<br><br><font color=\\\"white\\\">\"+myaccount+\"</font>\":myaccount\r\n                color: \"black\"\r\n            }\r\n            MouseArea{\r\n                anchors.fill: parent\r\n                hoverEnabled: true\r\n                onEntered: {\r\n                    root.highlightIndex = index\r\n                }\r\n                \r\n                onClicked: {\r\n                    root.clicked(myaccount)\r\n                    root.close()\r\n                    listClose()\r\n                }\r\n            }\r\n            \r\n            SvgView{\r\n                anchors.verticalCenter: parent.verticalCenter\r\n                anchors.right: parent.right\r\n                anchors.rightMargin: 20\r\n                width: defaultSize.width*myqq.windowScale\r\n                visible: root.highlightIndex == index\r\n                source: \"qrc:/images/button-quit.svg\"\r\n                property string qq: myaccount\r\n                MouseArea{\r\n                    anchors.fill: parent\r\n                    onClicked: {\r\n                        mymodel.remove(index)\r\n                        myqq.removeLoginedQQInfo(myaccount)//清除此账号的信息\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n    Component.onCompleted: {\r\n        var qq_list = myqq.getLoginedQQInfo()//读取已经登录过的qq的信息\r\n        for( var i=0;i<qq_list.length;++i ){\r\n            mymodel.append({\"myaccount\": qq_list[i].account, \"nick\": qq_list[i].nick, \"mysource\": qq_list[i].avatarSource})\r\n        }\r\n    }\r\n\r\n    ListView{\r\n        id:list\r\n        interactive: false\r\n        anchors.fill: parent\r\n        model: ListModel{id:mymodel}\r\n        delegate: component\r\n    }\r\n    \r\n    onFocusObjectChanged: {\r\n        if( isCanClose ){\r\n            root.close()\r\n            listClose()\r\n        } else\r\n            isCanClose = true\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Login/LoginPanel/LoginCheckBox.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\nimport mywindow 1.0\r\n\r\nCheckBox {\r\n    id:root\r\n    \r\n    style: CheckBoxStyle {\r\n        indicator: Item{\r\n            implicitHeight: image.implicitHeight\r\n            implicitWidth: image.implicitWidth\r\n            SvgView{\r\n                width: defaultSize.width*myqq.windowScale\r\n                source: control.checked?\"qrc:/images/checkBox-select.svg\":\"qrc:/images/checkBox-unselect.svg\"\r\n            }\r\n            SvgView{\r\n                id: image\r\n                width: defaultSize.width*myqq.windowScale\r\n                source: \"qrc:/images/checkBox-hover.svg\"\r\n                visible: mouse.hover\r\n                Component.onCompleted: root.height = width\r\n            }\r\n        }\r\n        label: Text{\r\n            text: control.text\r\n            font.pointSize: root.height/2\r\n        }\r\n    }\r\n    MouseArea{\r\n        id:mouse\r\n        anchors.fill: parent\r\n        property bool hover: false\r\n        hoverEnabled: true\r\n        onEntered: {\r\n            hover = true\r\n        }\r\n        onExited: hover = false\r\n        onClicked: {\r\n            parent.checked=!parent.checked\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Login/LoginPanel/LoginInputArea.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\nimport mywindow 1.0\r\n\r\nItem{\r\n    id:root\r\n    property bool qqlistopen: false\r\n    //color: \"red\"\r\n    TextField{\r\n        id: input_qq\r\n        font.pointSize: root.height/6\r\n        KeyNavigation.down: input_password\r\n        KeyNavigation.up: input_password\r\n        KeyNavigation.tab: KeyNavigation.down\r\n        text: utility.value(\"mainqq\", \"\")\r\n        \r\n\r\n        style: TextFieldStyle {\r\n            textColor: \"black\"\r\n            background: Item{\r\n                implicitWidth: border_qq.width-unfold_icon.width\r\n                implicitHeight: 25/64*border_qq.height\r\n                //color: \"black\"\r\n                SvgView {\r\n                    id: border_qq\r\n                    width: defaultSize.width*myqq.windowScale\r\n                    x: -5/220*width\r\n                    y: -6/64*height\r\n                    source: \"qrc:/images/inputBox1.svg\"\r\n                }\r\n            }\r\n        }\r\n        onTextChanged: {\r\n            myqq.userQQ=text\r\n        }\r\n        Component.onCompleted: {\r\n            input_qq.forceActiveFocus()\r\n        }\r\n    }\r\n    TextField{\r\n        id: input_password\r\n        anchors.top: input_qq.bottom\r\n        anchors.topMargin: 4/128*root.height\r\n        echoMode: TextInput.Password\r\n        font.pointSize: root.height/8\r\n        KeyNavigation.up: input_qq\r\n        KeyNavigation.down: input_qq\r\n        KeyNavigation.tab: KeyNavigation.down\r\n        validator: RegExpValidator{\r\n            regExp: /[0-9a-zA-Z`~\\!@\\#\\$%\\^&\\*\\(\\)\\-\\=_\\+\\[\\]\\{\\}\\\\\\|;\\:'\"<>\\?,\\.\\/]{6,16}/\r\n        }\r\n\r\n        text: myqq.userPassword\r\n        onTextChanged: {\r\n            //console.log(myqq.userPassword+\",\"+text)\r\n            myqq.userPassword=text\r\n        }\r\n\r\n        style: TextFieldStyle {\r\n            textColor: \"black\"\r\n            background: Item{\r\n                implicitWidth: border_password.width-soft_keyboard_icon.width\r\n                implicitHeight: 23/64*border_password.height\r\n                //color: \"blue\"\r\n                SvgView {\r\n                    id: border_password\r\n                    x: -5/220*width\r\n                    width: defaultSize.width*myqq.windowScale\r\n                    anchors.bottom: parent.bottom\r\n                    anchors.bottomMargin: -6/64*height\r\n                    source: \"qrc:/images/inputBox2.svg\"\r\n                }\r\n            }\r\n        }\r\n    }\r\n    SvgView {\r\n        id: unfold_icon\r\n        width: defaultSize.width*myqq.windowScale\r\n        source: \"qrc:/images/inputBox-more.svg\"\r\n        anchors.left: input_qq.right \r\n        anchors.leftMargin: -1/16*root.width\r\n        anchors.verticalCenter: input_qq.verticalCenter\r\n        property bool isCloseing: false\r\n        onIsCloseingChanged: {\r\n            if(isCloseing&&!mymouse1.hovered) {\r\n                unfold_icon.rotation = 0\r\n                isCloseing=false\r\n                qqlistopen = false\r\n            }\r\n        }\r\n        \r\n        Connections{\r\n            id: connection\r\n            target: null\r\n            onClicked:{\r\n                input_qq.text = qq//填充qq号码\r\n            }\r\n            onListClose:{\r\n                unfold_icon.isCloseing=true\r\n            }\r\n        }\r\n\r\n        MouseArea{\r\n            id: mymouse1\r\n            anchors.fill: parent\r\n            hoverEnabled: true\r\n            property bool hovered: false\r\n            \r\n            onEntered: hovered = true\r\n            onExited: hovered = false\r\n            onClicked: {\r\n                if( unfold_icon.isCloseing ){\r\n                    unfold_icon.rotation = 0\r\n                    unfold_icon.isCloseing=false\r\n                    qqlistopen = false\r\n                }else if( unfold_icon.rotation == 0 ){\r\n                    unfold_icon.rotation = 180\r\n                    qqlistopen = true\r\n                    var component = Qt.createComponent(\"AccountList.qml\");\r\n                    if (component.status == Component.Ready){\r\n                        var data={\"width\":21/22*root.width,\"x\": utility.mouseDesktopPos().x-mouse.x-unfold_icon.x,\"y\": utility.mouseDesktopPos().y-mouse.y-unfold_icon.y+input_qq.height}\r\n                        connection.target = component.createObject(input_qq, data);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n    \r\n    SvgView {\r\n        id: soft_keyboard_icon\r\n        width: defaultSize.width*myqq.windowScale\r\n        source: \"qrc:/images/soft-keyboard.svg\"\r\n        anchors.left: input_password.right\r\n        anchors.leftMargin: -1/16*root.width\r\n        anchors.verticalCenter: input_password.verticalCenter\r\n        property bool keyboardClose: true\r\n        property bool isCloseing: false\r\n        onIsCloseingChanged: {\r\n            if(isCloseing&&!mymouse2.hovered) {\r\n                keyboardClose=true\r\n                isCloseing=false\r\n            }\r\n        }\r\n        Connections{\r\n            id: connections\r\n            target: null\r\n            onInput:{\r\n                input_password.text+=arg\r\n            }\r\n            onBackspace:{\r\n                input_password.text = input_password.text.substr(0, input_password.text.length-1)\r\n            }\r\n            onKeyboardClose:{\r\n                soft_keyboard_icon.isCloseing=true\r\n            }\r\n        }\r\n        \r\n        MouseArea{\r\n            id: mymouse2\r\n            anchors.fill: parent\r\n            property bool hovered: false\r\n            hoverEnabled: true\r\n            onEntered: hovered = true\r\n            onExited: hovered = false\r\n            onClicked: {\r\n                if(soft_keyboard_icon.isCloseing){\r\n                    soft_keyboard_icon.keyboardClose=true\r\n                    soft_keyboard_icon.isCloseing=false\r\n                }else if( soft_keyboard_icon.keyboardClose){\r\n                    soft_keyboard_icon.keyboardClose=false\r\n                    var component = Qt.createComponent(\"../../Utility/KeyboardPage/SoftKeyboard.qml\");\r\n                    if (component.status == Component.Ready){\r\n                        var sprite = component.createObject(input_password);\r\n                        connections.target = sprite\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Login/LoginPanel/LoginPage.qml",
    "content": "import QtQuick 2.2\r\nimport utility 1.0\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\nimport QtQuick.Particles 2.0\r\nimport mywindow 1.0\r\nimport qqstars 1.0\r\nimport \"../../Utility\"\r\nimport \"../\"\r\n\r\nItem{\r\n    property alias contentItem: effect\r\n    \r\n    width: effect.actualWidth\r\n    height: effect.actualHeight\r\n    function reLogin(){\r\n        myqq.loginStatus = QQ.WaitLogin\r\n        animation_avatar.stop()//停止动画\r\n        avatar_image.x = -30/77*avatar_image.width//将头像位置复原\r\n    }\r\n    \r\n    MyRectangularGlow{\r\n        id: effect\r\n        glowRadius: 50\r\n        spread: 0.1\r\n        color: \"black\"\r\n        glowOpacity: 0.75\r\n        width: root.width\r\n        height: root.height\r\n        biasY: 20\r\n       \r\n        item:SvgView {\r\n            id: root\r\n            source: \"qrc:/images/login-panel2.svg\"\r\n            width: defaultSize.width*myqq.windowScale\r\n            \r\n            Connections{\r\n                target: myqq\r\n                onLoginStatusChanged:{\r\n                    if( myqq.loginStatus == QQ.Logining )\r\n                        animation_avatar.start()\r\n                }\r\n            }\r\n            ParticleSystem {\r\n                id: particles\r\n                anchors.fill: parent\r\n                //running: true\r\n                ImageParticle {\r\n                    source: \"qrc:/images/未标题-1.png\"\r\n                }\r\n                Emitter {\r\n                    id: pulseEmitter\r\n                    anchors.right: parent.right\r\n                    anchors.top: parent.top\r\n                    anchors.margins: 120\r\n                    emitRate: 10\r\n                    lifeSpan: 2000\r\n                    velocity: AngleDirection{\r\n                        magnitude: 35; \r\n                        magnitudeVariation: 20\r\n                        angle: -90\r\n                        angleVariation: 45\r\n                    }\r\n                    size: 5\r\n                    sizeVariation: 20\r\n                }\r\n            }\r\n            MyImage{\r\n                id:avatar_image\r\n                maskSource: \"qrc:/images/bit.bmp\"\r\n                width: 80*myqq.windowScale\r\n                height: width\r\n                sourceSize.width: width\r\n                source: myqq.avatar240\r\n                x:-30/80*width\r\n                anchors.verticalCenter: inputarea.verticalCenter\r\n\r\n\r\n                Connections{\r\n                    target: myqq\r\n                    onUserQQChanged:{\r\n                        avatar_image.source = myqq.avatar240\r\n                    }\r\n                }\r\n\r\n                onLoadError:{\r\n                    console.log(\"头像加载出错:\"+myqq.avatar240)\r\n                    source = \"qrc:/images/avatar.png\"\r\n                }\r\n                \r\n                SvgView{\r\n                    id: rect_border\r\n                    source: \"qrc:/images/avatar-border.svg\"\r\n                    anchors.centerIn: parent\r\n                    width: avatar_image.width*1.23\r\n                }\r\n        \r\n                Timer{\r\n                    id: timer_login\r\n                    interval: 10\r\n                    onTriggered: myqq.login()//开始登录\r\n                }\r\n        \r\n                NumberAnimation{\r\n                    id: animation_avatar\r\n                    target: avatar_image\r\n                    property: \"x\"\r\n                    duration: 300\r\n                    from: -30/77*avatar_image.width\r\n                    to: root.width/2 - avatar_image.width/2\r\n                    onStopped: timer_login.start()//必须在结束后启动定时器然后在定时器结束后在调用login()，不然会导致ui卡一下\r\n                }\r\n        \r\n               SvgView{\r\n                    id: user_status_icon\r\n                    width: defaultSize.width*myqq.windowScale\r\n                    anchors.right: parent.right\r\n                    anchors.bottom: parent.bottom\r\n                    anchors.margins: -0.02*avatar_image.width\r\n                    //sourceSize.width: width\r\n                    //width: 5/16*avatar_image.width\r\n                    enabled: myqq.loginStatus == QQ.WaitLogin\r\n                    source: \"qrc:/images/status-\"+myqq.stateToString+\"-1.svg\"\r\n                    MyMenu{\r\n                        id: menu_state\r\n                        styleSheet: \"QMenu::item:selected {\r\n                 background: #F07000;\r\n                 color:#E6FFFF;\r\n                 height:25px;\r\n             }\r\n             QMenu{\r\n                background-image: url(':/images/menu_background.png');\r\n             }\r\n             QMenu::icon{\r\n                padding-left:8px;\r\n             }\r\n             QMenu::item{\r\n                padding-left:32px;\r\n                padding-right:20px;\r\n                height:22px;\r\n             }\r\n             QMenu::separator {\r\n                  height: 1px;\r\n                  margin:5px 0px 5px 22px;\r\n                  background: #B2C0CD;\r\n             }\r\n        \"\r\n                        MyMenuItem{\r\n                            text: \"我在线上\"\r\n                            icon: \"qrc:/images/imonline.png\"\r\n                            onTriggered: {\r\n                                myqq.state = QQ.Online\r\n                            }\r\n                        }\r\n                        MyMenuItem{\r\n                            text: \"Q我吧\"\r\n                            icon: \"qrc:/images/imcallme.png\"\r\n                            onTriggered: {\r\n                                myqq.state = QQ.Callme\r\n                            }\r\n                        }\r\n                        MyMenuItem{\r\n                            text: \"离开\"\r\n                            icon: \"qrc:/images/imaway.png\"\r\n                            onTriggered: {\r\n                                myqq.state = QQ.Away\r\n                            }\r\n                        }\r\n                        MyMenuItem{\r\n                            text: \"忙碌\"\r\n                            icon: \"qrc:/images/imbusy.png\"\r\n                            onTriggered: {\r\n                                myqq.state = QQ.Busy\r\n                            }\r\n                        }\r\n                        MyMenuItem{\r\n                            text: \"请勿打扰\"\r\n                            icon: \"qrc:/images/imsilent.png\"\r\n                            onTriggered: {\r\n                                myqq.state = QQ.Silent\r\n                            }\r\n                        }\r\n                        MyMenuItem{\r\n                            text: \"隐身\"\r\n                            icon: \"qrc:/images/imhidden.png\"\r\n                            onTriggered: {\r\n                                myqq.state = QQ.Hidden\r\n                            }\r\n                        }\r\n                    }\r\n                    MouseArea{\r\n                        anchors.fill: parent\r\n                        onClicked: {\r\n                            menu_state.popup()\r\n                        }\r\n                    }\r\n                }\r\n                Text{\r\n                    text: myqq.userQQ\r\n                    font.pointSize: avatar_image.width/8\r\n                    anchors.horizontalCenter: parent.horizontalCenter\r\n                    anchors.top: parent.bottom\r\n                    anchors.topMargin: 10\r\n                    visible: myqq.loginStatus == QQ.Logining\r\n                }\r\n            }\r\n        \r\n            SvgView{\r\n                id:image_quit_icon\r\n                width: defaultSize.width*myqq.windowScale\r\n                source: \"qrc:/images/button-quit.svg\"\r\n                anchors.left: parent.left\r\n                anchors.top: parent.top\r\n                anchors.margins: 10\r\n                MouseArea{\r\n                    anchors.fill: parent\r\n                    onClicked: Qt.quit()\r\n                }\r\n            }\r\n        \r\n            SvgView {\r\n                id: image_qq_for_ubuntu\r\n                width: defaultSize.width*myqq.windowScale\r\n                //sourceSize.width: width\r\n                source: \"qrc:/images/QQ-for-ubuntu.svg\"\r\n                anchors.top: parent.top\r\n                anchors.right: parent.right\r\n                anchors.margins: 20\r\n            }\r\n            \r\n            LoginInputArea{\r\n                id: inputarea\r\n                width: 220*myqq.windowScale\r\n                height: 64*myqq.windowScale\r\n                visible: myqq.loginStatus == QQ.WaitLogin\r\n                anchors.left: avatar_image.right\r\n                anchors.leftMargin: 30\r\n                anchors.top: image_qq_for_ubuntu.bottom\r\n                anchors.topMargin: root.height/10\r\n                Component.onCompleted: {\r\n                    //console.log(width)\r\n                    //console.log(height)\r\n                }\r\n\r\n                LoginCheckBox{\r\n                    id: checkbox_rememberpassword\r\n                    //height:2/40*root.width\r\n                    checked: myqq.rememberPassword//myqq.value(\"rememberpassword\", 0)==1\r\n                    anchors.left: inputarea.left\r\n                    anchors.top: inputarea.bottom\r\n                    anchors.topMargin: root.height/12\r\n                    text: \"记住密码\"\r\n                    onCheckedChanged: {\r\n                        if( !checked ){\r\n                            checkbox_autologin.checked = false\r\n                            //myqq.removeValue(\"password\")//将密码置空\r\n                        }\r\n                    }\r\n                }\r\n                \r\n                LoginCheckBox{\r\n                    id:checkbox_autologin\r\n                    //height:2/40*root.width\r\n                    checked: myqq.autoLogin//myqq.value(\"autologin\", 0)==1\r\n                    anchors.right: inputarea.right\r\n                    anchors.rightMargin: 10\r\n                    anchors.top: inputarea.bottom\r\n                    anchors.topMargin: root.height/12\r\n                    text: \"自动登录\"\r\n                    onCheckedChanged: {\r\n                        if(checked)\r\n                            checkbox_rememberpassword.checked = true\r\n                    }\r\n                }\r\n            }\r\n            Connections{\r\n                target: myqq\r\n                onUserQQChanged:{\r\n                    checkbox_rememberpassword.checked = myqq.rememberPassword//myqq.value(\"rememberpassword\", 0)==1\r\n                    checkbox_autologin.checked = myqq.autoLogin//myqq.value(\"autologin\", 0)==1\r\n                }\r\n            }\r\n            Item{\r\n                id: progress_item\r\n                clip: true\r\n                anchors.bottom: parent.bottom\r\n                anchors.bottomMargin: root.height/4.2-height\r\n                visible: myqq.loginStatus == QQ.Logining\r\n                onVisibleChanged: {\r\n                    if(visible)\r\n                        progress_animation1.start()\r\n                    else{\r\n                        progress_animation1.stop()\r\n                    }\r\n                }\r\n        \r\n                width: root.implicitWidth\r\n                height: image_progress1.implicitHeight\r\n                Image{\r\n                    id: image_progress1\r\n                    source: \"qrc:/images/progress-bar.png\"\r\n                    width: root.width\r\n                    \r\n                    NumberAnimation{\r\n                        id:progress_animation1\r\n                        running: false\r\n                        target: image_progress1\r\n                        property: \"x\"\r\n                        from: 0\r\n                        to: root.width\r\n                        duration: 5000\r\n                        onStopped: {\r\n                            if( progress_item.visible )\r\n                                start()\r\n                        }\r\n                    }\r\n                }\r\n                Image{\r\n                    id: image_progress2\r\n                    source: \"qrc:/images/progress-bar.png\"\r\n                    width: root.width\r\n                    anchors.right: image_progress1.left\r\n                }\r\n            }\r\n            \r\n            MyLoginButton{\r\n                id:button_login\r\n                anchors.bottom: parent.bottom\r\n                anchors.bottomMargin: 30/250*root.height-height/2-1*height/defaultSize.height\r\n                width: defaultSize.width*myqq.windowScale\r\n\r\n                anchors.horizontalCenter: parent.horizontalCenter\r\n                text: myqq.loginStatus != QQ.WaitLogin?\"取    消\":\"登    录\"\r\n                font.pointSize: width/15\r\n                \r\n                onClicked: {\r\n                    if( myqq.loginStatus == QQ.WaitLogin ){\r\n                        if( myqq.userQQ!=\"\"&&myqq.userPassword!=\"\" ){\r\n                            myqq.loginStatus = QQ.Logining\r\n                            myqq.autoLogin = checkbox_autologin.checked\r\n                            myqq.rememberPassword = checkbox_rememberpassword.checked\r\n                            myqq.saveUserPassword()//保存密码\r\n                            utility.setValue(\"mainqq\", myqq.userQQ)//设置当前活动qq为myqq.userQQ\r\n                        }\r\n                    }else if( myqq.loginStatus == QQ.Logining ){\r\n                        reLogin()//调用重新登录\r\n                        myqq.loginStatus = QQ.WaitLogin\r\n                    }\r\n                }\r\n            }\r\n            SvgView{\r\n                id: button_setting\r\n                width: defaultSize.width*myqq.windowScale\r\n                source: \"qrc:/images/button-settings.svg\"\r\n                anchors.right: parent.right\r\n                anchors.verticalCenter: button_login.verticalCenter\r\n                visible: myqq.loginStatus == QQ.WaitLogin\r\n                MouseArea{\r\n                    anchors.fill: parent\r\n                    onClicked: {\r\n                        main.openSettingPage()//进行设置\r\n                    }\r\n                }\r\n            }\r\n        \r\n            Component.onCompleted: {\r\n                //if( myqq.value(\"autologin\", 0)==1 )//此账号如果设置了自动登录\r\n                if(myqq.autoLogin)//如果是自动登录\r\n                    myqq.loginStatus = QQ.Logining\r\n                forceActiveFocus()\r\n            }\r\n            Keys.onEnterPressed: {\r\n                button_login.clicked()\r\n            }\r\n            Keys.onReturnPressed: {\r\n                button_login.clicked()\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Login/MyLoginButton.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\n\r\nSvgView{\r\n    id:root\r\n    //sourceSize.width: width\r\n    property alias text: button_text.text\r\n    property alias font: button_text.font\r\n    source: {\r\n        if( mouse.pressed )\r\n            return \"qrc:/images/button-login-press.svg\"\r\n        else if(mouse.hover)\r\n            return \"qrc:/images/button-login-hover.svg\"\r\n        else\r\n            return \"qrc:/images/button-login.svg\"\r\n    }\r\n\r\n    signal clicked\r\n    Rectangle{\r\n        radius: 10\r\n        anchors.fill: parent\r\n        color: \"#888\"\r\n        visible: !root.enabled\r\n    }\r\n\r\n    Text {\r\n        id: button_text\r\n        anchors.centerIn: parent\r\n        color: \"white\"\r\n    }\r\n    MouseArea{\r\n        id:mouse\r\n        enabled: root.enabled\r\n        property bool hover: false\r\n        anchors.fill: parent\r\n        hoverEnabled: true\r\n        onEntered: {\r\n            hover = true\r\n        }\r\n        onExited: {\r\n            hover = false\r\n        }\r\n        onClicked: {\r\n            root.clicked()\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Login/SettingPage.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\nimport utility 1.0\r\nimport mywindow 1.0\r\nimport \"../Utility\"\r\nimport \"../Utility/ComboBox\"\r\n\r\nItem{\r\n    width: effect.actualWidth\r\n    height: effect.actualHeight\r\n    MyRectangularGlow{\r\n        id: effect\r\n        glowRadius: 50\r\n        spread: 0.1\r\n        color: \"black\"\r\n        glowOpacity: 0.75\r\n        width: root.width\r\n        height: root.height\r\n        biasY: 20\r\n\r\n        item:SvgView {\r\n            id:root\r\n            source: \"qrc:/images/login-panel.svg\"\r\n            width: defaultSize.width*myqq.windowScale\r\n            SvgView{\r\n                id:image_quit_icon\r\n                width: defaultSize.width*myqq.windowScale\r\n                source: \"qrc:/images/button-quit.svg\"\r\n                anchors.left: parent.left\r\n                anchors.top: parent.top\r\n                anchors.margins: 10\r\n                MouseArea{\r\n                    anchors.fill: parent\r\n                    onClicked: {\r\n                        main.openLoginPage()//返回登录\r\n                    }\r\n                }\r\n            }\r\n    \r\n            SvgView {\r\n                id: image_qq_for_ubuntu\r\n                width: defaultSize.width*myqq.windowScale\r\n                source: \"qrc:/images/QQ-for-ubuntu.svg\"\r\n                anchors.top: parent.top\r\n                anchors.right: parent.right\r\n                anchors.margins: 20\r\n            }\r\n            Grid{\r\n                anchors.horizontalCenter: parent.horizontalCenter\r\n                anchors.top: image_qq_for_ubuntu.bottom\r\n                anchors.topMargin: root.height/10\r\n                \r\n                columns: 2\r\n                rowSpacing: root.width/20\r\n                columnSpacing: root.height/20\r\n                horizontalItemAlignment: Qt.AlignHCenter\r\n                verticalItemAlignment: Qt.AlignVCenter\r\n                \r\n                MyTextField{\r\n                    id: proxy_location_input\r\n                    enabled: proxy_combo.currentIndex != 0\r\n                    width: root.width/2.5\r\n                    height: width/8\r\n                    title: \"地址:\"\r\n                    text: utility.value(\"proxyLocation\", \"\")\r\n                }\r\n                MyTextField{\r\n                    id: proxy_port_input\r\n                    enabled: proxy_combo.currentIndex != 0\r\n                    width: root.width/2.5\r\n                    height: width/8\r\n                    title: \"端口:\"\r\n                    text: utility.value(\"proxyPort\", \"\")\r\n                }\r\n                MyTextField{\r\n                    id: proxy_username_input\r\n                    enabled: proxy_combo.currentIndex != 0\r\n                    width: root.width/2.5\r\n                    height: width/8\r\n                    title: \"账户:\"\r\n                    text: utility.value(\"proxyUsername\", \"\")\r\n                }\r\n                MyTextField{\r\n                    id: proxy_password_input\r\n                    enabled: proxy_combo.currentIndex != 0\r\n                    width: root.width/2.5\r\n                    height: width/8\r\n                    title: \"密码:\"\r\n                    text: utility.value(\"proxyPassword\", \"\")\r\n                }\r\n                Item{\r\n                    width: root.width/2.5\r\n                    height: width/8\r\n                    Text {\r\n                        id: proxy_type_text\r\n                        text: \"类型:\"\r\n                        font.pointSize: parent.height/2\r\n                        anchors.verticalCenter: parent.verticalCenter\r\n                    }\r\n                    \r\n                    MyComboBox{\r\n                        id: proxy_combo\r\n                        height: parent.height\r\n                        anchors.left: proxy_type_text.right\r\n                        anchors.right: parent.right\r\n                        currentIndex: utility.value(\"proxyTypeIndex\", 0)\r\n                        model: ListModel {\r\n                            ListElement { text: \"不使用代理\"; value: Utility.NoProxy}\r\n                            ListElement { text: \"HTTP代理\"; value: Utility.HttpProxy}\r\n                            ListElement { text: \"SOCKS5代理\"; value: Utility.Socks5Proxy}\r\n                        }\r\n                    }\r\n                }\r\n                MyButton {\r\n                    text: \"测  试\"\r\n                    width: root.width/4\r\n                    height: width/4\r\n                    visible: proxy_combo.currentIndex != 0\r\n                    font.pointSize: proxy_type_text.font.pointSize\r\n                    onClicked:{\r\n                        console.log(\"fdsafds\")\r\n                        utility.setApplicationProxy(proxy_combo.currentValue, proxy_location_input.text, proxy_port_input.text, proxy_username_input.text, proxy_password_input.text)\r\n                        utility.httpGet(testNetwork, \"http://d.web2.qq.com/channel/poll2\")\r\n                        button_affirm.enabled = false\r\n                        enabled = false\r\n                    }\r\n                    \r\n                    function testNetwork(error ,data) {\r\n                        var temp1 = utility.value(\"proxyLocation\", \"\")\r\n                        var temp2 = utility.value(\"proxyPort\", \"\")\r\n                        var temp3 = utility.value(\"proxyUsername\", \"\")\r\n                        var temp4 = utility.value(\"proxyPassword\", \"\")\r\n                        var temp5 = utility.value(\"proxyType\", Utility.NoProxy)\r\n                        utility.setApplicationProxy(temp5, temp1, temp2, temp3, temp4)//将代理设置复原\r\n                        button_affirm.enabled = true\r\n                        enabled = true\r\n                        if( error )\r\n                            myqq.showWarningInfo(\"测试失败\")\r\n                        else\r\n                            myqq.showWarningInfo(\"测试通过\")\r\n                    }\r\n                    \r\n                }\r\n            }\r\n\r\n            MyLoginButton{\r\n                id: button_affirm\r\n                anchors.bottom: parent.bottom\r\n                anchors.bottomMargin: 30/250*root.height-height/2-1*height/defaultSize.height\r\n                width: defaultSize.width*myqq.windowScale\r\n                anchors.horizontalCenter: parent.horizontalCenter\r\n                text:\"确    认\"\r\n                font.pointSize: width/15\r\n                onClicked: {\r\n                    utility.setApplicationProxy(proxy_combo.currentValue, proxy_location_input.text, proxy_port_input.text, proxy_username_input.text, proxy_password_input.text)\r\n                    utility.setValue(\"proxyLocation\", proxy_location_input.text)\r\n                    utility.setValue(\"proxyPort\", proxy_port_input.text)\r\n                    utility.setValue(\"proxyUsername\", proxy_username_input.text)\r\n                    utility.setValue(\"proxyPassword\", proxy_password_input.text)\r\n                    utility.setValue(\"proxyType\", proxy_combo.currentValue)\r\n                    utility.setValue(\"proxyTypeIndex\", proxy_combo.currentIndex)\r\n                    main.openLoginPage()//返回登录\r\n                }\r\n            }\r\n            Keys.onEnterPressed: {\r\n                button_affirm.clicked()\r\n            }\r\n            Keys.onReturnPressed: {\r\n                button_affirm.clicked()\r\n            }\r\n        }    \r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Login/main.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Particles 2.0\r\nimport mywindow 1.0\r\nimport utility 1.0\r\n//import Qt.labs.settings 1.0\r\nimport QQItemInfo 1.0\r\nimport MyTextEditPlugin 1.0\r\nimport \"../Utility\"\r\nimport \"../MainPanel\"\r\nimport \"LoginPanel\"\r\nimport \"../Chat\"\r\n\r\nMyWindow{\r\n    id:main\r\n    windowIcon: \"qrc:/images/avatar.png\"\r\n    actualWidth: 350*myqq.windowScale+200\r\n    actualHeight: 250*myqq.windowScale+150\r\n    visible: true//可视的\r\n    contentItemAreaTop: login_page.contentItem.y///////////////////////////设置\r\n    contentItemAreaBottom: contentItemAreaTop+login_page.contentItem.height//响应\r\n    contentItemAreaLeft: login_page.contentItem.x/////////////////////////鼠标的\r\n    contentItemAreaRight: contentItemAreaLeft+login_page.contentItem.width//区域\r\n    noBorder: true//无边框的\r\n    removable: true//可移动的\r\n    fixedSize: true//固定大小的\r\n    dockableWindow: false//可停靠的\r\n    topHint: false//窗口保持在最前端\r\n    noNotifyIcon: true//隐藏任务栏图标\r\n    windowGlow: false//是否开启阴影\r\n    color: \"transparent\"\r\n\r\n    function openSettingPage() {//进行设置\r\n        settings_page.enabled = true\r\n        flipable.flipped = false\r\n    }\r\n    function openLoginPage() {//打开登录面板\r\n        login_page.enabled = true\r\n        flipable.flipped = true\r\n    }\r\n    Connections{\r\n        target: myqq\r\n        onError:{\r\n            if( message.indexOf(\"验证码\")<0 ){\r\n                login_page.reLogin()//重新登录\r\n                myqq.closeCodeWindow()//关闭输入验证码的窗口\r\n            }else{\r\n                myqq.updataCode()//刷新验证码\r\n            }\r\n        }\r\n    }\r\n\r\n    Connections{\r\n        target: systemTray\r\n        onActivated:{\r\n            if( arg == MySystemTrayIcon.Trigger ) {\r\n                main.showFront()\r\n            }\r\n        }\r\n        onTriggered: {\r\n            if(arg == \"打开主面板\"){\r\n                main.showFront()\r\n            }\r\n        }\r\n    }\r\n    \r\n    ParticleSystem {//粒子系统\r\n        id: particles\r\n        anchors.centerIn: parent\r\n        width: main.actualWidth\r\n        height: main.actualHeight\r\n        Age{\r\n            system: particles\r\n            anchors.left: parent.left\r\n            height: parent.height\r\n            width: 80\r\n            once: true\r\n            lifeLeft: 3000\r\n            advancePosition: false\r\n            \r\n        }\r\n        Age{\r\n            system: particles\r\n            anchors.right: parent.right\r\n            height: parent.height\r\n            width: 80\r\n            once: true\r\n            lifeLeft: 3000\r\n            advancePosition: false\r\n            \r\n        }\r\n        \r\n        Age{\r\n            system: particles\r\n            anchors.bottom: parent.bottom\r\n            height: 80\r\n            width: parent.width\r\n            once: true\r\n            lifeLeft: 3000\r\n            advancePosition: false\r\n            \r\n        }\r\n        \r\n        ImageParticle {\r\n            source: \"qrc:/images/star.png\"\r\n            groups: ['star']\r\n            alpha: 0.2\r\n            alphaVariation: 0.1\r\n            colorVariation: 2\r\n            autoRotation: true\r\n            rotationVariation: 360\r\n            rotationVelocity: 40\r\n        }\r\n        Emitter {\r\n            id: pulseEmitter\r\n            anchors.top: parent.top\r\n            width: parent.width\r\n            group: 'star'\r\n            emitRate: 8\r\n            lifeSpan: parent.height*1000/40\r\n            velocityFromMovement: 20\r\n            velocity: AngleDirection{\r\n                angle: 90\r\n                angleVariation: 50\r\n                magnitude: 90\r\n                magnitudeVariation: 10\r\n            }\r\n            acceleration: AngleDirection{\r\n                angle: -90\r\n                magnitude: 5\r\n                magnitudeVariation: 2\r\n            }\r\n            size: 20\r\n            sizeVariation: 5\r\n            endSize: 0\r\n        }\r\n        \r\n    }\r\n    \r\n    Flipable {\r\n         id: flipable\r\n         anchors.fill: parent\r\n         property bool flipped: true\r\n         onFlippedChanged:{\r\n             timer.start()\r\n         }\r\n         Timer{\r\n             id: timer\r\n             interval: 200\r\n             onTriggered: {\r\n                 if( flipable.flipped ){\r\n                     settings_page.enabled = false\r\n                 }else{\r\n                     login_page.enabled = false\r\n                 }\r\n             }\r\n         }\r\n\r\n         front: LoginPage{\r\n             id: login_page\r\n             anchors.right: parent.right\r\n         }\r\n         back: SettingPage{\r\n             id: settings_page;\r\n             enabled: false\r\n             anchors.right: parent.right\r\n         }\r\n    \r\n         transform: Rotation {\r\n             id: rotation\r\n             origin.x: flipable.width/2\r\n             origin.y: flipable.height/2\r\n             axis.x: 0; axis.y: 1; axis.z: 0     // set axis.y to 1 to rotate around y-axis\r\n             angle: 0    // the default angle\r\n         }\r\n    \r\n         states: State {\r\n             name: \"back\"\r\n             PropertyChanges { target: rotation; angle: 180 }\r\n             when: !flipable.flipped\r\n         }\r\n\r\n         transitions: Transition {\r\n             NumberAnimation { \r\n                 target: rotation; \r\n                 property: \"angle\"; \r\n                 duration: timer.interval ;\r\n                 easing.type: Easing.InQuart\r\n             }\r\n         }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/MainPanel/ListPage/AllListPage.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\nimport mywindow 1.0\r\n\r\nTabView {\r\n    id: frame\r\n    property int old_current:0\r\n    \r\n    Tab {\r\n        active: true\r\n        id: friend_list\r\n        FriendList{\r\n            id: rect1\r\n            width: parent.width\r\n            height: parent.height\r\n            NumberAnimation{\r\n                id: animat1\r\n                target: rect1\r\n                duration: 200\r\n                running: false\r\n                easing.type: Easing.InCubic\r\n                property: \"x\"\r\n                from: -width\r\n                to:0\r\n            }\r\n            Connections{\r\n                target: frame\r\n                onCurrentIndexChanged: {\r\n                    if(frame.currentIndex==0){\r\n                        animat1.start()\r\n                        frame.old_current = 0\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n    Tab {\r\n        active: true\r\n        GroupAndDiscuPage{\r\n            id:rect2\r\n            width: parent.width\r\n            height: parent.height\r\n            NumberAnimation{\r\n                id: animat2\r\n                target: rect2\r\n                duration: 200\r\n                running: false\r\n                easing.type: Easing.InCubic\r\n                property: \"x\"\r\n                from: frame.old_current==0?width:-width\r\n                to:0\r\n            }\r\n            Connections{\r\n                target: frame\r\n                onCurrentIndexChanged: {\r\n                    if(frame.currentIndex==1){\r\n                        animat2.start()\r\n                        frame.old_current = 1\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n    Tab { \r\n        active: true\r\n        id: recent_list\r\n        RecentList{\r\n            id:rect3\r\n            width: parent.width\r\n            height: parent.height\r\n            \r\n            NumberAnimation{\r\n                id: animat3\r\n                target: rect3\r\n                duration: 200\r\n                running: false\r\n                easing.type: Easing.InCubic\r\n                property: \"x\"\r\n                from: width\r\n                to:0\r\n            }\r\n            Connections{\r\n                target: frame\r\n                onCurrentIndexChanged: {\r\n                    if(frame.currentIndex==2){\r\n                        animat3.start()\r\n                        frame.old_current = 2\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        \r\n    }\r\n\r\n    style: TabViewStyle {\r\n        //tabOverlap: 10\r\n        tabsMovable : true\r\n        tabsAlignment:Qt.AlignHCenter\r\n        tab: Item{\r\n            implicitHeight: icon.height+20\r\n            implicitWidth: control.width/3\r\n            //width: control.width/3\r\n            \r\n            SvgView{\r\n                id: icon\r\n                anchors.horizontalCenter: parent.horizontalCenter\r\n                source: {\r\n                    if(index==0)\r\n                        return \"qrc:/images/friendList_select.svg\"\r\n                    else if(index==1)\r\n                        return \"qrc:/images/groupList_select.svg\"\r\n                    else\r\n                        return \"qrc:/images/recentList_select.svg\"\r\n                }\r\n            }\r\n        }\r\n        frame: Item {}\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/MainPanel/ListPage/DiscuList.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\nimport utility 1.0\r\nimport \"../\"\r\nimport \"../../Utility\"\r\nimport QQItemInfo 1.0\r\n\r\nItem{\r\n    id: root\r\n    clip: true\r\n    \r\n    function getDiscusListFinished(error, data) {//获取讨论组列表完成\r\n        if(error){\r\n            myqq.getDiscusList(getDiscusListFinished) //讨论组列表\r\n            return\r\n        }\r\n        data = JSON.parse(data)\r\n        if(data.retcode ==0 ) {\r\n            var list_info = data.result.dnamelist\r\n            for( var i=0; i< list_info.length;++i ) {\r\n                var info = myqq.createDiscuInfo(list_info[i].did) \r\n                info.nick = list_info[i].name//设置昵称\r\n                mymodel.append({\"obj_info\": info})\r\n            }\r\n        }\r\n    }\r\n    Component.onCompleted: {\r\n        myqq.getDiscusList(getDiscusListFinished) //讨论组列表\r\n    }\r\n    MyScrollView{\r\n        anchors.fill: parent\r\n        Item{\r\n            height: mymodel.count*40+10\r\n            width: root.width\r\n            implicitHeight: height\r\n            implicitWidth: width\r\n\r\n            ListView{\r\n               id: list\r\n               interactive: false\r\n               anchors.fill: parent\r\n               model: ListModel{\r\n                   id:mymodel\r\n               }\r\n               spacing :10\r\n               delegate: component\r\n            }\r\n        }\r\n    }\r\n    \r\n    Component{\r\n        id: component\r\n        Item{\r\n            id: item_root\r\n            width: parent.width\r\n            height: avatar.height\r\n            property DiscuInfo myinfo: obj_info\r\n\r\n            MyImage{\r\n                id: avatar\r\n                x:10\r\n                width:40\r\n                height: 40\r\n                sourceSize.width: width\r\n                source: \"qrc:/images/avatar.png\"\r\n                maskSource: \"qrc:/images/bit.bmp\"\r\n            }\r\n            Text{\r\n                id:text_nick\r\n                anchors.top: avatar.top\r\n                anchors.left: avatar.right\r\n                anchors.leftMargin: 10\r\n                font.pointSize: 14\r\n                text: item_root.myinfo.aliasOrNick\r\n            }\r\n            MouseArea{\r\n                anchors.fill: parent\r\n                onDoubleClicked: {\r\n                    myqq.addChatPage(item_root.myinfo.uin, QQItemInfo.Discu)\r\n                }\r\n            }\r\n        }\r\n    }    \r\n}\r\n"
  },
  {
    "path": "qml/MainPanel/ListPage/FriendList.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\nimport utility 1.0\r\nimport \"../\"\r\nimport \"../../Utility\"\r\nimport QQItemInfo 1.0\r\n\r\nItem{\r\n    id: friendlist_main\r\n    width: parent.width\r\n    height: parent.height\r\n    clip:true\r\n    function addModel( name, index ,obj_friendListData ){\r\n        mymodel.append({\"obj_groupingName\": name, \"obj_groupingIndex\": index, \"obj_friendListData\":obj_friendListData})\r\n    }\r\n    function insertModel( sort, name, index ,obj_friendListData ){\r\n        mymodel.insert(sort, {\"obj_groupingName\": name, \"obj_groupingIndex\": index, \"obj_friendListData\":obj_friendListData})\r\n    }\r\n\r\n    function getFriendListFinished(error, data) {//获取好友列表完成\r\n        if(error){\r\n            myqq.getFriendList(getFriendListFinished) //获取好友列表\r\n            return\r\n        }\r\n        data = JSON.parse(data)\r\n        if( data.retcode == 0) {\r\n            var marknames = data.result.marknames//备注信息\r\n            for( var i=0; i<marknames.length;++i ) {\r\n                var obj_info = myqq.createFriendInfo(marknames[i].uin)\r\n                if(obj_info){\r\n                    obj_info.alias = marknames[i].markname//储存备注信息\r\n                }\r\n            }\r\n            for( i=0; i< data.result.friends.length;++i ) {\r\n                myqq.addFriendUin(data.result.friends[i].uin)\r\n                //将所有好友的uin都添加进去，为判断一个uin是否为陌生人做基础\r\n            }\r\n            \r\n            var categories = data.result.categories//分组信息\r\n            if(categories.length>0&&categories[0].index>0)//如果分组数目大于0，但是第一个分组的index不为0\r\n                addModel(\"我的好友\", 0, data.result)//则将默认的\"我的好友\"分组加进去\r\n            var arr = new Array\r\n            for(i=0; i<categories.length;++i){\r\n                arr.push(categories[i])//现将每个对象都放到数组当中\r\n            }\r\n            arr.sort(function(a,b){\r\n                //console.log(\"调用了排序,\"+(a.sort>b.sort))\r\n                return a.sort>b.sort?1:-1//将数组按照里边的sort属性排序\r\n            })\r\n\r\n            for(i=0; i<arr.length; ++i){//遍历数组\r\n                addModel(arr[i].name, arr[i].index, data.result)//增加分组\r\n            }\r\n        }else{\r\n            console.debug(\"好友列表获取失败：\"+data.retcode)\r\n        }\r\n    }\r\n    function getOnlineFriendsFinished(error, data){//获取在线好友完成\r\n        if(error){\r\n            myqq.getOnlineFriends(getOnlineFriendsFinished)//再去获取\r\n        }\r\n        data = JSON.parse(data)\r\n        if(data.retcode == 0){\r\n            for(var i in data.result){\r\n                var info = myqq.createFriendInfo(data.result[i].uin)\r\n                info.stateToString = data.result[i].status//设置状态\r\n            }\r\n        }\r\n    }\r\n\r\n    Component.onCompleted: {\r\n        myqq.getOnlineFriends(getOnlineFriendsFinished)//获取在线好友\r\n        myqq.getFriendList(getFriendListFinished) //获取好友列表\r\n    }\r\n\r\n    MyScrollView{\r\n        anchors.fill: parent\r\n        Item{\r\n            height: list.contentHeight+10\r\n            width: friendlist_main.width\r\n            implicitHeight: height\r\n            implicitWidth: width\r\n            ListView{\r\n               id: list\r\n               interactive: false\r\n               anchors.fill: parent\r\n               model: ListModel{\r\n                   id:mymodel\r\n               }\r\n               spacing :10\r\n               delegate: component1\r\n            }\r\n        }\r\n    }\r\n    Component{\r\n        id: component1\r\n        Item{\r\n            id: root\r\n            clip: true\r\n            property string name: obj_groupingName\r\n            property int groupingIndex:obj_groupingIndex\r\n            property var friendListData: obj_friendListData\r\n            onFriendListDataChanged: {\r\n                var friends = friendListData.friends//好友列表\r\n                var friends_info = friendListData.info//好友信息\r\n                for( var i=0; i< friends.length;++i ) {\r\n                    if( friends[i].categories==groupingIndex ){//判断是否是本分组的内容\r\n                        var info = myqq.createFriendInfo(friends_info[i].uin)\r\n                        info.nick = friends_info[i].nick//设置昵称\r\n                        var data = {\"obj_info\": info}\r\n                        mymodel2.append(data)//增加好友 \r\n                    }\r\n                }\r\n            }\r\n\r\n            property alias model: mymodel2\r\n            height: titleBar.height\r\n            width: parent.width\r\n            \r\n            state: \"close\"\r\n            function stateSwitch(){\r\n                if( state==\"close\" )\r\n                    state = \"unfold\"\r\n                else\r\n                    state=\"close\"\r\n            }\r\n        \r\n            states: [\r\n                State {\r\n                    name: \"close\"\r\n                    PropertyChanges {\r\n                        target: root\r\n                        height: titleBar.height\r\n                    }\r\n                },\r\n                State {\r\n                    name: \"unfold\"\r\n                    PropertyChanges {\r\n                        target: root\r\n                        height: titleBar.height+list2.contentHeight+10\r\n                    }\r\n                }\r\n            ]\r\n            \r\n            Item{\r\n                id: titleBar\r\n                width: parent.width\r\n                height: Math.max(image_icon.implicitHeight, text_name.implicitHeight)\r\n                Text{\r\n                    id: image_icon\r\n                    x:10\r\n                    anchors.verticalCenter: text_name.verticalCenter\r\n                    text: root.state == \"close\"?\"+\":\"-\"\r\n                    font.pointSize: 16\r\n                }\r\n            \r\n                Text{\r\n                    id: text_name\r\n                    text: name\r\n                    anchors.left: image_icon.right\r\n                    anchors.leftMargin: 10\r\n                    font.pointSize: 10\r\n                    font.bold: true\r\n                }\r\n                MouseArea{\r\n                    anchors.fill: parent\r\n                    onClicked: {\r\n                        root.stateSwitch()\r\n                    }\r\n                }\r\n            }\r\n        \r\n            ListView{\r\n                id: list2\r\n                interactive: false\r\n                model: ListModel{\r\n                    id:mymodel2\r\n                    \r\n                    property int onlineIndex: 0//在线好友的序列，初始为0\r\n                    \r\n                    function stateToOnline(index){\r\n                        //当序列为index的model项调用此函数后，会将他前移到onlineIndex尾部\r\n                        if(index>=onlineIndex)\r\n                            move(index, onlineIndex++, 1)//移动此项\r\n                    }\r\n                    function stateToOffline(index){\r\n                        //当序列为index的model项调用此函数后，会将他前移到尾部\r\n                        if(index<=count-1){\r\n                            --onlineIndex\r\n                            move(index, count-1, 1)\r\n                        }\r\n                    }\r\n                }\r\n                spacing: 10\r\n                delegate: component2\r\n                anchors.top: titleBar.bottom\r\n                anchors.topMargin: 10\r\n                width: parent.width\r\n                height: parent.height\r\n            }\r\n            Component{\r\n                id: component2\r\n                Item{\r\n                    id: item_root\r\n                    width: parent.width\r\n                    height: avatar.height\r\n                    property FriendInfo myinfo: obj_info\r\n                    \r\n                    Component.onCompleted: {\r\n                        if(myinfo.state != FriendInfo.Offline){//如果不是离线状态\r\n                            mymodel2.stateToOnline(index)//将自己移动到前面\r\n                        }\r\n                    }\r\n                    Connections{\r\n                        target: myinfo\r\n                        onStateChanged:{//如果状态改变\r\n                            if(myinfo.state == FriendInfo.Offline){//如果是离线状态\r\n                                mymodel2.stateToOffline(index)//将自己移动到最后\r\n                            }else{\r\n                                mymodel2.stateToOnline(index)//否则就往上移动\r\n                            }\r\n                        }\r\n                    }\r\n        \r\n                    MyImage{\r\n                        id: avatar\r\n                        x:10\r\n                        width:40\r\n                        height: 40\r\n                        sourceSize.width: width\r\n                        grayscale: myinfo.state==FriendInfo.Offline\r\n                        maskSource: \"qrc:/images/bit.bmp\"\r\n                        cache: false\r\n                        source: item_root.myinfo.avatar40\r\n                        onLoadError: {\r\n                            myinfo.avatar40 = \"qrc:/images/avatar.png\"\r\n                        }\r\n                    }\r\n                    Text{\r\n                        id:text_nick\r\n                        anchors.top: avatar.top\r\n                        anchors.left: avatar.right\r\n                        anchors.leftMargin: 10\r\n                        font.pointSize: 14\r\n                        text: myinfo.aliasOrNick//myqq.value(info.uin+\"alias\", info.nick)\r\n                    }\r\n                    Text{\r\n                        id:text_signature//个性签名\r\n                        anchors.left: text_nick.left\r\n                        anchors.bottom: avatar.bottom\r\n                        font.pointSize: 8\r\n                        text: myinfo.QQSignature//myqq.value(info.uin+\"signature\", \"获取中...\")\r\n                    }\r\n                    MouseArea{\r\n                        anchors.fill: parent\r\n                        onDoubleClicked: {\r\n                            myqq.addChatPage(myinfo.uin, QQItemInfo.Friend)\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/MainPanel/ListPage/GroupAndDiscuPage.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\n\r\nItem{\r\n    TabView{\r\n        anchors.fill: parent\r\n        Tab{\r\n            title: \"QQ群\"\r\n            active: true\r\n            GroupList{\r\n                width: parent.width\r\n                height: parent.height\r\n            }\r\n        }\r\n        Tab{\r\n            title: \"讨论组\"\r\n            active: true\r\n            DiscuList{\r\n                width: parent.width\r\n                height: parent.height\r\n            }\r\n        }\r\n        style: TabViewStyle {\r\n            //tabOverlap: 10\r\n            frameOverlap: -10\r\n            tabsMovable : true\r\n            tabsAlignment:Qt.AlignHCenter\r\n            tab:Rectangle {\r\n                color: styleData.selected ? \"#f07000\" :\"#eee\"\r\n                border.color:  \"#888\"\r\n                border.width: 1\r\n                implicitWidth: Math.max(text.width + 4, 80)\r\n                implicitHeight: 20\r\n                radius: 10\r\n                Rectangle{\r\n                    height: parent.implicitHeight\r\n                    width: height\r\n                    x:index==1?0:parent.width-width\r\n                    color: parent.color\r\n                    border.width: parent.border.width\r\n                    border.color: parent.border.color\r\n                    Rectangle{\r\n                        height: parent.height-2*width\r\n                        width: parent.border.width\r\n                        anchors.verticalCenter: parent.verticalCenter\r\n                        x:index==0?0:parent.width-width\r\n                        color: parent.color\r\n                    }\r\n                }\r\n\r\n                Text {\r\n                    id: text\r\n                    anchors.centerIn: parent\r\n                    text: styleData.title\r\n                    color: styleData.selected ? \"white\" : \"black\"\r\n                }\r\n            }\r\n            frame: Item {}\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/MainPanel/ListPage/GroupList.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\nimport utility 1.0\r\nimport \"../\"\r\nimport \"../../Utility\"\r\nimport QQItemInfo 1.0\r\n\r\nItem{\r\n    id: root\r\n    clip: true\r\n    \r\n    function getGroupListFinished( error, data ) {\r\n        if(error){\r\n            myqq.getGroupList(getGroupListFinished) //获取群列表\r\n            return\r\n        }\r\n        \r\n        data = JSON.parse(data)\r\n        if(data.retcode ==0 ) {\r\n            var groupmarknames = data.result.gmarklist//群备注信息\r\n            var i=0;\r\n            \r\n            for( i=0; i<groupmarknames.length;++i ) {\r\n                var obj_info = myqq.createGroupInfo(groupmarknames[i].uin)\r\n                if(obj_info){\r\n                    obj_info.alias = groupmarknames[i].markname//储存备注信息\r\n                }\r\n            }\r\n\r\n            var list_info = data.result.gnamelist\r\n            for( i=0; i< list_info.length;++i ) {\r\n                var info = myqq.createGroupInfo(list_info[i].gid)\r\n                info.nick = list_info[i].name\r\n                info.code = list_info[i].code\r\n                mymodel.append({\"obj_info\": info})\r\n            }\r\n        }\r\n    }\r\n    Component.onCompleted: {\r\n        myqq.getGroupList(getGroupListFinished)\r\n    }\r\n    MyScrollView{\r\n        anchors.fill: parent\r\n        Item{\r\n            height: list.contentHeight+10\r\n            width: root.width\r\n            implicitHeight: height\r\n            implicitWidth: width\r\n            ListView{\r\n               id: list\r\n               interactive: false\r\n               anchors.fill: parent\r\n               model: ListModel{\r\n                   id:mymodel\r\n               }\r\n               spacing :10\r\n               delegate: component\r\n            }\r\n        }\r\n    }\r\n    \r\n    Component{\r\n        id: component\r\n        Item{\r\n            id: item_root\r\n            width: parent.width\r\n            height: avatar.height\r\n            property var myinfo: obj_info\r\n\r\n            MyImage{\r\n                id: avatar\r\n                x:10\r\n                width:40\r\n                height: 40\r\n                sourceSize.width: width\r\n                maskSource: \"qrc:/images/bit.bmp\"\r\n                cache: false\r\n                source: myinfo.avatar40\r\n                onLoadError: {\r\n                    item_root.myinfo.avatar40 = \"qrc:/images/avatar.png\"\r\n                }\r\n            }\r\n            Text{\r\n                id:text_nick\r\n                anchors.top: avatar.top\r\n                anchors.left: avatar.right\r\n                anchors.leftMargin: 10\r\n                font.pointSize: 14\r\n                text: myinfo.aliasOrNick\r\n            }\r\n            MouseArea{\r\n                anchors.fill: parent\r\n                onDoubleClicked: {\r\n                    myqq.addChatPage(item_root.myinfo.uin, QQItemInfo.Group)//打开聊天页\r\n                }\r\n            }\r\n        }\r\n    }    \r\n}\r\n"
  },
  {
    "path": "qml/MainPanel/ListPage/RecentList.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\nimport QQItemInfo 1.0\r\nimport \"../\"\r\nimport \"../../QQItemInfo\"\r\nimport \"../../Utility\"\r\n\r\nItem{\r\n    id: root\r\n    clip:true\r\n    \r\n    Component.onCompleted: {\r\n        myqq.getRecentList(getRecentListFinished) //获取最近联系人\r\n    }\r\n    function getRecentListFinished(error, data){//当获取最近联系人列表完成后\r\n        if(error){\r\n            myqq.getRecentList(getRecentListFinished) //获取最近联系人\r\n            return\r\n        }\r\n\r\n        data = JSON.parse(data)\r\n        if( data.retcode==0 ) {\r\n            data = data.result\r\n            for(var i=0;i<data.length;++i){\r\n                var info\r\n                switch(data[i].type) {\r\n                case 0://0为好友\r\n                    info=myqq.createFriendInfo(data[i].uin)\r\n                    break\r\n                case 1://1为群\r\n                    info=myqq.createGroupInfo(data[i].uin)\r\n                    break\r\n                case 2://2为讨论组\r\n                    info=myqq.createDiscuInfo(data[i].uin)\r\n                    break\r\n                default:break\r\n                }\r\n                mymodel.addEnd(info)//添加最近联系人\r\n            }\r\n        }\r\n    }\r\n    \r\n    Connections{\r\n        target: myqq\r\n        onAddRecentContacts:{//收到增加最近联系人的信号\r\n            mymodel.addBegin(info)\r\n        }\r\n    }\r\n\r\n    MyScrollView{\r\n        anchors.fill: parent\r\n        Item{\r\n            height: list.contentHeight+10\r\n            width: root.width\r\n            implicitHeight: height\r\n            implicitWidth: width\r\n            \r\n            ListView{\r\n               id: list\r\n               \r\n               anchors.fill: parent\r\n               interactive: false\r\n               model: ListModel{\r\n                   id:mymodel\r\n                   function addEnd(item_info){\r\n                       for(var i=0; i<mymodel.count; ++i)\r\n                           if(mymodel.get(i).obj_info == item_info){\r\n                               return\r\n                           }\r\n                       mymodel.append({\"obj_info\": item_info})\r\n                   }\r\n\r\n                   function addBegin(item_info){//判断一个对象是否存在于list中，是的话返回他的index\r\n                       for(var i=0; i<mymodel.count; ++i)\r\n                           //console.debug(mymodel.get(i).obj_info+\",\"+item_info)\r\n                           if(mymodel.get(i).obj_info == item_info){\r\n                               mymodel.move(i,0,1)\r\n                               return\r\n                           }\r\n                       mymodel.append({\"obj_info\": item_info})\r\n                   }\r\n               }\r\n               //spacing :10\r\n               delegate: component\r\n            }\r\n        }\r\n    }\r\n    Component{\r\n        id: component\r\n        Item{\r\n            id: item_root\r\n            property QQItemInfo myinfo: obj_info\r\n            \r\n            width: parent.width\r\n            height: avatar.height+16\r\n            \r\n\r\n            MyImage{\r\n                id: avatar\r\n                x:10\r\n                width:40\r\n                height: 40\r\n                sourceSize.width: width\r\n                anchors.verticalCenter: parent.verticalCenter\r\n                cache: false\r\n                grayscale: myinfo.mytype == QQItemInfo.Friend&&myinfo.state==FriendInfo.Offline//是否为黑白图\r\n                maskSource: \"qrc:/images/bit.bmp\"\r\n                source: myinfo.avatar40\r\n                onLoadError: {\r\n                    myinfo.avatar40 = \"qrc:/images/avatar.png\"\r\n                }\r\n            }\r\n            Text{\r\n                id:text_nick\r\n                anchors.top: avatar.top\r\n                anchors.left: avatar.right\r\n                anchors.leftMargin: 10\r\n                font.pointSize: 14\r\n                text: myinfo.aliasOrNick\r\n            }\r\n            Rectangle{\r\n                id: rect_message_count\r\n                width: text_message_count.implicitWidth+10\r\n                height: text_message_count.implicitHeight+10\r\n                anchors.bottom: parent.bottom\r\n                anchors.right: parent.right\r\n                anchors.rightMargin: 15\r\n                anchors.bottomMargin: 5\r\n                color: \"red\"\r\n                radius: height\r\n                visible: myinfo.unreadMessagesCount>0\r\n                Text{\r\n                    id: text_message_count\r\n                    anchors.centerIn: parent\r\n                    text: myinfo.unreadMessagesCount//未读消息的个数\r\n                    color: \"white\"\r\n                    onTextChanged: {\r\n                        if(text == \"100\"){\r\n                            text = \"99+\"\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            Rectangle{\r\n                height: 1\r\n                anchors.left: avatar.left\r\n                anchors.right: rect_message_count.right\r\n                anchors.bottom: parent.bottom\r\n                color: \"#ddd\"\r\n            }\r\n\r\n            MouseArea{\r\n                anchors.fill: parent\r\n                onDoubleClicked: {\r\n                    myqq.addChatPage(myinfo.uin, myinfo.mytype)\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/MainPanel/MainPanelPage.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\nimport mywindow 1.0\r\nimport \"ListPage\"\r\n\r\nItem{\r\n    id: root\r\n    clip:true\r\n    Text{\r\n        id: text_nick\r\n        x: 10\r\n        font.pointSize: 16\r\n        font.bold: true\r\n        color: \"black\"\r\n        text: myqq.nick\r\n    }\r\n    Text{\r\n        id: text_signature\r\n        anchors.left: text_nick.left\r\n        anchors.top: text_nick.bottom\r\n        anchors.topMargin: 10\r\n        color: \"black\"\r\n        font.pointSize: 8\r\n        Component.onCompleted: {\r\n            myqq.getQQSignature(myqq.userQQ, getMeSignature)//去网络请求签名\r\n        }\r\n\r\n        function getMeSignature(data){//获得自己的个性签名成功后\r\n            data = JSON.parse(data)\r\n            if( data.retcode==0 ){\r\n                text = data.result[0].lnick\r\n            }\r\n        }\r\n    }\r\n    AllListPage{\r\n        anchors.top: text_signature.bottom\r\n        anchors.topMargin: 1\r\n        width: root.width-4\r\n        anchors.horizontalCenter: parent.horizontalCenter\r\n        anchors.bottom: parent.bottom\r\n        anchors.bottomMargin: 2\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/MainPanel/main.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\nimport QtQuick.Window 2.1\r\nimport utility 1.0\r\nimport \"../Utility\"\r\nimport \"../Chat\"\r\nimport qqstars 1.0\r\n//import Qt.labs.settings 1.0\r\n\r\nMyWindow{\r\n    id:main\r\n    visible: true//可视的\r\n    noBorder: true//无边框的\r\n    removable: true//可移动的\r\n    fixedSize: false//固定大小的\r\n    dockableWindow: true//可停靠的\r\n    topHint: true//窗口保持在最前端\r\n    noNotifyIcon: true//隐藏任务栏图标\r\n    color: \"transparent\"\r\n    centered: false\r\n    minimumWidth: 220\r\n    minimumHeight: 400\r\n    maximumWidth: 500\r\n    maximumHeight: 700\r\n    \r\n    width: 240\r\n    height: 500\r\n\r\n    Component.onCompleted: {\r\n        width = Math.max(200, minimumWidth)\r\n        height = Math.max(500, minimumHeight)\r\n        main.x = Screen.desktopAvailableWidth - main.actualWidth\r\n        main.y = 20\r\n    }\r\n    function windowToActive(){//将窗口转为活动状态\r\n        main.showFront()\r\n        if(main.visible) {\r\n            main.showWindow()//从停靠状态转为可停靠状态\r\n        }\r\n    }\r\n\r\n    Connections{\r\n        target: systemTray\r\n        onActivated:{\r\n            if( arg == MySystemTrayIcon.Trigger ) {\r\n                windowToActive()//将窗口转为活动状态\r\n            }\r\n        }\r\n        onTriggered: {\r\n            if(arg == \"打开主面板\"){\r\n                windowToActive()//将窗口转为活动状态\r\n            }\r\n        }\r\n    }\r\n    \r\n    Rectangle{\r\n        anchors.fill: parent\r\n        radius: 10\r\n        gradient: Gradient {\r\n                        GradientStop { position: 0 ; color:  \"#EEEDEC\" }\r\n                        GradientStop { position: 120/main.height ; color:  \"#E7E5E4\" }\r\n                        GradientStop { position: 120/main.height+0.01 ; color:  \"#f9f9f8\" }\r\n                        GradientStop { position: 1 ; color:  \"#f9f9f8\" }\r\n                    }\r\n        SvgView{\r\n            id:image_quit_icon\r\n            width: defaultSize.width*myqq.windowScale\r\n            source: \"qrc:/images/button-quit.svg\"\r\n            anchors.left: parent.left\r\n            anchors.top: parent.top\r\n            anchors.margins: 10\r\n            MouseArea{\r\n                anchors.fill: parent\r\n                onClicked: {\r\n                    myqq.state = QQ.Offline//将状态改为离线\r\n                    Qt.quit()\r\n                }\r\n            }\r\n        }\r\n        SvgView{\r\n            id:image_minimize_icon\r\n            width: defaultSize.width*myqq.windowScale\r\n            source: \"qrc:/images/button-minimize.svg\"\r\n            anchors.top: image_quit_icon.top\r\n            anchors.left: image_quit_icon.right\r\n            MouseArea{\r\n                anchors.fill: parent\r\n                onClicked: {\r\n                    main.showMinimized()\r\n                }\r\n            }\r\n        }\r\n        MainPanelPage{\r\n            id: panel_page\r\n            anchors.top: image_minimize_icon.bottom\r\n            anchors.topMargin: 10\r\n            anchors.bottom: parent.bottom\r\n            width: parent.width\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/QQItemInfo/DiscuInfo.qml",
    "content": "import QtQuick 2.2\r\nimport QQItemInfo 1.0\r\n\r\nDiscuInfo{\r\n    userQQ: myqq.userQQ\r\n}\r\n"
  },
  {
    "path": "qml/QQItemInfo/FriendInfo.qml",
    "content": "import QQItemInfo 1.0\r\nimport QtQuick 2.2\r\n\r\nFriendInfo{\r\n    id: root\r\n    \r\n    property bool getImageing: false//记录是否正在获取图片\r\n    \r\n    userQQ: myqq.userQQ\r\n    onUinChanged: {//如果uin变了\r\n        myqq.getFriendQQ( uin, getQQFinished )//获取好友的真实qq号\r\n    }\r\n    \r\n    function getUserDataFinished(error, data){//获取资料完成\r\n        if(error){//如果出错了\r\n            myqq.getUserData(uin, getUserDataFinished)//去获取好友资料\r\n            return\r\n        }\r\n        \r\n        data = JSON.parse(data)\r\n        if( data.retcode==0 ){\r\n            nick = data.result.nick//设置昵称\r\n        }\r\n    }\r\n\r\n    function getQQFinished(error, data){//获取好友真实qq后调用的函数\r\n        //console.log(root.uin+\"获得真实QQ结束：\"+data)\r\n        if(error){\r\n            myqq.getFriendQQ( uin, getQQFinished )//获取好友的真实qq号\r\n            return\r\n        }\r\n        \r\n        data = JSON.parse(data)\r\n        if( data.retcode==0 ){\r\n            account = data.result.account\r\n            if( avatar40==\"qrc:/images/avatar.png\" )\r\n                getAvatar(40)//去获取头像\r\n        }\r\n    }\r\n    function getAvatarFinished( error, path ,name){\r\n        getImageing = false//获取图像结束\r\n        if(error){//如果出错了\r\n            getAvatar(40)//重新获取\r\n            return\r\n        }\r\n\r\n        var imageName = path+\"/\"+name\r\n        avatar40 = imageName//保存自己头像的地址\r\n        //console.log(nick+\"获取头像完成：\"+imageName)\r\n    }\r\n    function getQQSignatureFinished(error, data){//获取个性签名完成\r\n        if(error){\r\n            myqq.getQQSignature( uin, getQQSignatureFinished )//获取个性签名\r\n            return\r\n        }\r\n        \r\n        data = JSON.parse(data)\r\n        if( data.retcode==0 ){\r\n            QQSignature = data.result[0].lnick//储存个性签名\r\n        }\r\n    }\r\n    onHttpGetQQSignature:{//如果收到c++端发来的去获取个性签名的信号\r\n        myqq.getQQSignature( uin, getQQSignatureFinished )//获取个性签名\r\n    }\r\n    function getAvatar(size){\r\n        if(account!=\"\"&&!getImageing){\r\n            getImageing = true//正在获取头像\r\n            myqq.downloadImage(QQItemInfo.Friend\r\n                               , \"http://q.qlogo.cn/headimg_dl?spec=\"+String(size)+\"&dst_uin=\"+account\r\n                               , account, String(size), getAvatarFinished)//下载头像\r\n        }\r\n    }\r\n   \r\n    onAvatar40Changed: {\r\n        if( avatar40==\"qrc:/images/avatar.png\" )\r\n            getAvatar(40)\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/QQItemInfo/GroupInfo.qml",
    "content": "import QtQuick 2.2\r\nimport QQItemInfo 1.0\r\n\r\nGroupInfo{\r\n    id: root\r\n    property bool getImageing: false//记录是否正在获取图片\r\n    \r\n    userQQ: myqq.userQQ\r\n    onCodeChanged: {\r\n        //console.log(nick+\"将要获取真实qq\")\r\n        if(code!=\"\"){\r\n            myqq.getFriendQQ(code, getQQFinished)//获得真实qq\r\n        }\r\n    }\r\n    \r\n    onAccountChanged: {\r\n        if(account==\"\"&&code!=\"\")\r\n            myqq.getFriendQQ(nick, getQQFinished)//获得真实qq\r\n    }\r\n\r\n    function getQQFinished(error, data){//获取真实群号后调用的函数\r\n        if(error){\r\n            myqq.getFriendQQ(code, getQQFinished)\r\n            return\r\n        }\r\n\r\n        data = JSON.parse(data)\r\n        if( data.retcode==0 ){\r\n            account = data.result.account\r\n            //console.log(code+\"的真实qq：\"+account)\r\n            if(avatar40==\"qrc:/images/avatar.png\")\r\n                getAvatar(40)\r\n        }\r\n    }\r\n    function getAvatarFinished( error, path ,name){\r\n        getImageing=false//将正在获取头像置为false\r\n        if(error){//如果出错了\r\n            getAvatar(40)//重新获取\r\n            return\r\n        }\r\n        var imageName = path+\"/\"+name\r\n        avatar40 = imageName\r\n    }\r\n    function getAvatar(size){\r\n        if(account!=\"\"&&!getImageing){\r\n            getImageing = true//置为true，不然可能会多次请求头像\r\n            myqq.downloadImage(QQItemInfo.Group\r\n                               , \"http://p.qlogo.cn/gh/\"+account+\"/\"+account+\"/\"+String(size)\r\n                               , account, String(size), getAvatarFinished)//下载头像\r\n        }\r\n    }\r\n    onAvatar40Changed: {\r\n        if(avatar40==\"qrc:/images/avatar.png\")\r\n            getAvatar(40)\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/CodeInput.qml",
    "content": "import mywindow 1.0\r\nimport QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\nimport utility 1.0\r\nimport qqstars 1.0\r\n\r\nMyWindow{\r\n    id: root_window\r\n    visible: true//可视的\r\n    color: \"transparent\"\r\n    noBorder: true//无边框的\r\n    removable: true//可移动的\r\n    fixedSize: true//固定大小的\r\n    dockableWindow: false//可停靠的\r\n    topHint: false//窗口保持在最前端\r\n    noNotifyIcon: true//隐藏任务栏图标\r\n    modality : Qt.ApplicationModal\r\n    width: root_page.width\r\n    height: root_page.height\r\n    \r\n    property string code: code_input.text\r\n    property var backFun//验证码获取成功后调用此函数\r\n    property alias source: code_image.source\r\n\r\n    function updateCode(){\r\n        var temp = source\r\n        source = \"\"\r\n        source = temp\r\n        code_input.text = \"\"\r\n    }\r\n    SvgView {\r\n        id:root_page\r\n        width: 300*myqq.windowScale\r\n        source: \"qrc:/images/login-panel.svg\"\r\n        SvgView{\r\n            id:image_quit_icon\r\n            width: defaultSize.width*myqq.windowScale\r\n            source: \"qrc:/images/button-quit.svg\"\r\n            anchors.left: parent.left\r\n            anchors.top: parent.top\r\n            anchors.margins: 10\r\n            MouseArea{\r\n                anchors.fill: parent\r\n                onClicked: root_window.close()\r\n            }\r\n        }\r\n        Text{\r\n            id: text_code\r\n            text: \"请输入验证码\"\r\n            anchors.left: parent.left\r\n            anchors.top: parent.top\r\n            anchors.leftMargin: root_page.width/15\r\n            anchors.topMargin: root_page.height/6\r\n            color: \"#f47421\"\r\n            font.pointSize: root_page.height/25\r\n        }\r\n        TextField{\r\n            id: code_input\r\n            anchors.left: code_image.left\r\n            anchors.top: code_image.bottom\r\n            anchors.topMargin: 10\r\n            width: code_image.width\r\n            height: root_page.height/12\r\n            font.pointSize: text_code.font.pointSize\r\n            style: TextFieldStyle {\r\n                    textColor: \"black\"\r\n                    background: BorderImage {\r\n                        source: \"qrc:/images/background_input.png\"\r\n                        border.left: 5; border.top: 5\r\n                        border.right: 5; border.bottom: 5\r\n                    }\r\n                }\r\n            Component.onCompleted: code_input.forceActiveFocus()\r\n        }\r\n        Image{\r\n            id: code_image\r\n            width: 130\r\n            height: 53\r\n            cache: false\r\n            anchors.horizontalCenter: parent.horizontalCenter\r\n            anchors.top :text_code.top\r\n            anchors.topMargin: root_page.height/12\r\n\r\n            MouseArea{\r\n                anchors.fill: parent\r\n                onClicked: {\r\n                    updateCode()\r\n                }\r\n            }\r\n        }\r\n        MyButton{\r\n            id: button_affirm\r\n            anchors.bottom: parent.bottom\r\n            anchors.bottomMargin: root_page.height/20\r\n            width: 19/42*parent.width\r\n            anchors.horizontalCenter: parent.horizontalCenter\r\n            text:\"确    认\"\r\n            font.pointSize: width/15\r\n            onClicked: {\r\n                if( myqq.loginStatus == QQ.Logining&&code_input.text!=\"\" ) {\r\n                    backFun(code_input.text)\r\n                }\r\n            }\r\n        }\r\n        Keys.onEnterPressed: {\r\n            button_affirm.clicked()\r\n        }\r\n        Keys.onReturnPressed: {\r\n            button_affirm.clicked()\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/ComboBox/MyComboBox.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\n\r\nItem{\r\n    id: root\r\n    signal accepted\r\n    property int currentIndex\r\n    property var currentValue\r\n    property ListModel model\r\n    property MyComboBoxComponent mycomboboxcomponent\r\n\r\n    onCurrentIndexChanged: {\r\n        mytext.text = model.get(currentIndex).text\r\n        currentValue = model.get(currentIndex).value\r\n    }\r\n\r\n    property alias currentText: mytext.text\r\n    property bool hovered: false\r\n    property bool pressed: false\r\n    property bool isComboBoxCloseing: false\r\n    onIsComboBoxCloseingChanged: {\r\n        if(isComboBoxCloseing&&!root.hovered){\r\n            pressed = false\r\n            isComboBoxCloseing = false\r\n        }\r\n    }\r\n    \r\n    BorderImage {\r\n        id: background\r\n        anchors.fill: parent\r\n        source: \"qrc:/images/background_input.png\"\r\n        border.left: 5; border.top: 5\r\n        border.right: 5; border.bottom: 5\r\n        Text {\r\n            id: mytext\r\n            anchors.verticalCenter: parent.verticalCenter\r\n            anchors.left: parent.left\r\n            anchors.leftMargin: 5\r\n            text: model.get(0).text\r\n            font.pointSize: root.height/2\r\n        }\r\n        SvgView {\r\n            source: \"qrc:/images/inputBox-more.svg\"\r\n            rotation: root.pressed?180:0\r\n            anchors.right: parent.right\r\n            anchors.rightMargin: 5\r\n            anchors.verticalCenter: parent.verticalCenter\r\n        }\r\n        MouseArea{\r\n            id: mymouse\r\n            anchors.fill: parent\r\n            hoverEnabled: true\r\n            onEntered: root.hovered=true\r\n            onExited: root.hovered=false\r\n\r\n            onClicked: {\r\n                root.pressed=!root.pressed\r\n                if(isComboBoxCloseing){\r\n                    isComboBoxCloseing = false\r\n                }else if( root.pressed ){\r\n                    var component = Qt.createComponent(\"MyComboBoxComponent.qml\");\r\n                    if (component.status == Component.Ready){\r\n                        var temp = utility.mouseDesktopPos();\r\n                        var data = {\"root\":root, \"mymodel\":model, \"x\":temp.x-mouse.x, \"y\":temp.y+root.height-mouse.y+5, \"width\": root.width, \"height\": root.height*model.count, \"visible\":true}\r\n                        mycomboboxcomponent = component.createObject(root, data);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/ComboBox/MyComboBoxComponent.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Window 2.0\r\n\r\nWindow{\r\n    id: rootwindow\r\n    flags: Qt.SplashScreen\r\n    color: \"transparent\"\r\n    property bool isCanClose: false\r\n    property ListModel mymodel\r\n    property var root\r\n    \r\n    onFocusObjectChanged: {\r\n        if( isCanClose ){\r\n            root.isComboBoxCloseing=true\r\n            close()\r\n        } else\r\n            isCanClose = true\r\n    }\r\n    \r\n    Rectangle{\r\n        anchors.fill: parent\r\n        color: \"white\"\r\n        radius: 5\r\n        border.width: 1\r\n        border.color: \"#f07000\"\r\n    }\r\n\r\n    ListView{\r\n        id: list\r\n        interactive: false\r\n        anchors.fill: parent\r\n        model: mymodel\r\n        delegate: Component{\r\n            Item{\r\n                width: root.width\r\n                height: root.height\r\n                Rectangle{\r\n                    width: parent.width-4\r\n                    height: parent.height-4\r\n                    anchors.centerIn: parent\r\n                    color: \"#f07900\"\r\n                    radius: 5\r\n                    visible: mymouse.hovered\r\n                }\r\n\r\n                Text {\r\n                    id: text\r\n                    anchors.verticalCenter: parent.verticalCenter\r\n                    anchors.left: parent.left\r\n                    anchors.leftMargin: 5\r\n                    text: model.text\r\n                    color: mymouse.hovered?\"white\":\"black\"\r\n                    font.pointSize: parent.height/2\r\n                }\r\n                MouseArea{\r\n                    id: mymouse\r\n                    anchors.fill: parent\r\n                    hoverEnabled: true\r\n                    property bool hovered: false\r\n                    \r\n                    onEntered: {\r\n                        hovered = true\r\n                    }\r\n\r\n                    onExited: {\r\n                        hovered = false\r\n                    }\r\n\r\n                    onClicked: {\r\n                        root.pressed=false\r\n                        root.currentIndex = index\r\n                        root.accepted()\r\n                        rootwindow.close()\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/KeyboardPage/SoftKeyboard.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Window 2.1\r\nimport mywindow 1.0\r\n\r\nWindow{\r\n    id:root\r\n    visible: true\r\n    property bool is: false\r\n    x: utility.mouseDesktopPos().x - 200\r\n    y: utility.mouseDesktopPos().y + 13\r\n    width: 450*myqq.windowScale\r\n    height: 2/7*width\r\n    \r\n    flags: Qt.SplashScreen\r\n    signal input(var arg)\r\n    signal backspace(var arg)\r\n    signal keyboardClose\r\n    Rectangle {\r\n        anchors.fill: parent\r\n        radius: 3\r\n        border.width:1\r\n        border.color: \"#F07000\"\r\n        gradient: Gradient {\r\n                        GradientStop { position: 0 ; color: \"#E7E5E4\" }\r\n                        GradientStop { position: 1 ; color: \"#D9D7D6\" }\r\n                    }\r\n    }\r\n    SvgView{\r\n        width: defaultSize.width*myqq.windowScale\r\n        anchors.top: parent.top\r\n        anchors.right: parent.right\r\n        anchors.margins: 2\r\n        source: \"qrc:/images/inputBox-close.svg\"\r\n        MouseArea{\r\n            anchors.fill: parent\r\n            onClicked: {\r\n                root.close()\r\n                keyboardClose()\r\n            }\r\n        }\r\n    }\r\n\r\n    Component.onCompleted: {\r\n        object.createKeyboard()\r\n    }\r\n    QtObject{\r\n        id: object\r\n        property string ascii1_1: \"0123456789`-=[]\\\\;',./\"\r\n        property string ascii1_2: \")!@#$%^&*(~_+{}|:\\\"<>?\"\r\n        property string ascii2_1: \"abcdefghijklmnopqrstuvwxyz\"\r\n        property string ascii2_2: \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\r\n        \r\n        function randomOrder (targetArray)\r\n        {\r\n            var arrayLength = targetArray.length//先创建一个正常顺序的数组\r\n            var tempArray1 = new Array();\r\n            for (var i = 0; i < arrayLength; i ++){\r\n                tempArray1 [i] = i\r\n            }\r\n            var tempArray2 = new Array();//再根据上一个数组创建一个随机乱序的数组\r\n            for (var i = 0; i < arrayLength; i ++){//从正常顺序数组中随机抽出元素\r\n                tempArray2 [i] = tempArray1.splice (Math.floor (Math.random () * tempArray1.length) , 1)\r\n            }\r\n            var tempArray3 = new Array();//最后创建一个临时数组存储 根据上一个乱序的数组从targetArray中取得数据\r\n            for (var i = 0; i < arrayLength; i ++){\r\n                tempArray3 [i] = targetArray [tempArray2 [i]]\r\n            }\r\n            return tempArray3//返回最后得出的数组\r\n        }\r\n        function createObject(parent, data) {\r\n            var component = Qt.createComponent(\"SoftKeyboardButton.qml\");\r\n            if (component.status == Component.Ready){\r\n                return component.createObject(parent, data);\r\n            }\r\n        }\r\n        function createKeyboard(){\r\n            var data = {\"text1\": \"Shift\", \"isShiftButton\": true,\"width\": root.width/8, \"height\":root.width/17}\r\n            var shift = createObject(row2, data)\r\n            var temp = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];\r\n            temp = randomOrder(temp)//随机排序\r\n            for( var i=0;i<11;++i ){\r\n                data = {\"width\": root.width/17, \"height\":root.width/17,\"text1\": ascii1_1[temp[i]],\"text2\": ascii1_2[temp[i]],\"switchButton\": shift,\"backFun\": input}\r\n                createObject(row1, data);\r\n            }\r\n            data = {\"text1\": \"Backspace\",\"width\": root.width/6, \"height\":root.width/17,\"backFun\": backspace}\r\n            var backsoace = createObject(row1,data);\r\n            for( i=11;i<21;++i ){\r\n                data = {\"width\": root.width/17, \"height\":root.width/17,\"text1\": ascii1_1[temp[i]],\"text2\": ascii1_2[temp[i]],\"switchButton\": shift,\"backFun\": input}\r\n                createObject(row2, data);\r\n            }\r\n            data = {\"text1\": \"CapsLock\",\"width\": root.width/6, \"height\":root.width/17,\"isShiftButton\":true}\r\n            var capslock = createObject(row2,data);\r\n            \r\n            temp = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];\r\n            temp = randomOrder(temp)//随机排序\r\n            for( i=0;i<13;++i ){\r\n                data = {\"width\": root.width/17, \"height\":root.width/17,\"text1\": ascii2_1[temp[i]],\"text2\": ascii2_2[temp[i]],\"switchButton\": capslock,\"backFun\": input}\r\n                createObject(row3, data);\r\n            }\r\n            for( i=13;i<26;++i ){\r\n                data = {\"width\": root.width/17, \"height\":root.width/17,\"text1\": ascii2_1[temp[i]],\"text2\": ascii2_2[temp[i]],\"switchButton\": capslock,\"backFun\": input}\r\n                createObject(row4, data);\r\n            }\r\n        }\r\n    }\r\n\r\n    Grid{\r\n        anchors.centerIn: parent\r\n        spacing: 3\r\n        rows:4\r\n        horizontalItemAlignment : Qt.AlignHCenter\r\n        Row{id:row1;spacing: 3}\r\n        Row{id:row2;spacing: 3}\r\n        Row{id:row3;spacing: 3}\r\n        Row{id:row4;spacing: 3}\r\n    }\r\n    \r\n    onFocusObjectChanged: {\r\n        if( is ){\r\n            root.close()\r\n            keyboardClose()\r\n        }\r\n        else\r\n            is = true\r\n    }\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "qml/Utility/KeyboardPage/SoftKeyboardButton.qml",
    "content": "import QtQuick 2.2\r\n\r\nRectangle{\r\n    id: root\r\n    border.width: 1//control.activeFocus ? 2 : 1\r\n    border.color: \"#888\"\r\n    radius: 4\r\n    property string text1: \"\"\r\n    property string text2: \"\"\r\n    property Item switchButton: null\r\n    property bool shiftText: false\r\n    property bool isShiftButton: false\r\n    property bool isLetter: false\r\n    property var backFun//回调函数，按下按键就调用这个函数\r\n    signal trigger(var arg)\r\n    onTrigger: {\r\n        if( backFun )\r\n            backFun(arg)\r\n    }\r\n\r\n    Connections{\r\n        target: (isShiftButton||isLetter)?null:switchButton\r\n        onTrigger: {\r\n            shiftText = !shiftText\r\n        }\r\n    }\r\n\r\n    Text{\r\n        text:text1\r\n        anchors.left: parent.left\r\n        anchors.bottom: parent.bottom\r\n        anchors.margins: 5\r\n        visible: text2!=\"\"\r\n        color: shiftText?\"#999\":\"black\"\r\n        font.bold: shiftText?false:true\r\n        font.pointSize: root.width/3\r\n    }\r\n    Text{\r\n        text:text2\r\n        anchors.top: parent.top\r\n        anchors.right: parent.right\r\n        anchors.margins: 5\r\n        visible: text2!=\"\"\r\n        color: !shiftText?\"#999\":\"black\"\r\n        font.bold: !shiftText?false:true\r\n        font.pointSize: root.width/3\r\n    }\r\n    \r\n    Text{\r\n        text: text1\r\n        anchors.centerIn: parent\r\n        visible: text2==\"\"\r\n        font.pointSize: root.width/7\r\n    }\r\n\r\n    MouseArea{\r\n        id:mouse\r\n        anchors.fill: parent\r\n        hoverEnabled: true\r\n        property bool mouseArea: false\r\n        onEntered: {\r\n            mouseArea = true\r\n        }\r\n        onExited: {\r\n            mouseArea = false\r\n        }\r\n\r\n        onClicked: {\r\n            if(isShiftButton){\r\n                shiftText =!shiftText\r\n                trigger(text1)\r\n            }else if( text2==\"\" )\r\n                trigger(text1)\r\n            else{\r\n                if( shiftText )\r\n                    trigger(text2)\r\n                else\r\n                    trigger(text1)\r\n            }\r\n        }\r\n    }\r\n    gradient: Gradient {\r\n                    GradientStop { \r\n                        position: 0\r\n                        color: {\r\n                            if(isShiftButton&&shiftText){\r\n                                return \"#f09000\"\r\n                            }else\r\n                                return (mouse.pressed||mouse.mouseArea)?\"#f09000\":\"#fff\"\r\n                        }\r\n                    }\r\n                    GradientStop { \r\n                        position: 1 \r\n                        color: {\r\n                            if(isShiftButton&&shiftText){\r\n                                return \"#f07000\"\r\n                            }else\r\n                                return (mouse.pressed||mouse.mouseArea)?\"#f07000\":\"#eee\"\r\n                        }\r\n                    }\r\n                }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/MyButton.qml",
    "content": "import QtQuick 2.2\r\n\r\nRectangle {\r\n    id: root\r\n    property alias pressed: mymouse.pressed\r\n    property bool hovered: false\r\n    property alias font: text.font\r\n    property alias text: text.text\r\n    signal clicked\r\n    implicitWidth: 80\r\n    implicitHeight: 20\r\n    radius: 6\r\n    border.width: 1\r\n    border.color: \"#aaa\"\r\n    gradient: Gradient {\r\n        GradientStop { position: 0 ; color: {\r\n                if(!root.enabled)\r\n                    return \"#888\"\r\n                if( root.pressed )\r\n                    return \"#ff9000\"\r\n                if( root.hovered )\r\n                    return \"#eee\"\r\n                return \"#fff\"\r\n            }\r\n        }\r\n        GradientStop { position: 1 ; color: {\r\n                if(!root.enabled)\r\n                    return \"#777\"\r\n                if( root.pressed )\r\n                    return \"#f07000\"\r\n                if( root.hovered )\r\n                    return \"#ddd\"\r\n                return \"#eee\"\r\n            }\r\n        }\r\n    }\r\n    Text{\r\n        id: text\r\n        text: parent.text\r\n        anchors.centerIn: parent\r\n        color: parent.pressed?\"white\":\"black\"\r\n    }\r\n    MouseArea{\r\n        id: mymouse\r\n        anchors.fill: parent\r\n        hoverEnabled: true\r\n        onClicked: {\r\n            root.clicked()\r\n        }\r\n        onEntered: {\r\n            root.hovered = true\r\n        }\r\n        onExited: {\r\n            root.hovered = false\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/MyMessageBox.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\n\r\nMyWindow {\r\n    id:root\r\n    visible: true//可视的\r\n    noBorder: true//无边框的\r\n    removable: true//可移动的\r\n    fixedSize: true//固定大小的\r\n    dockableWindow: false//可停靠的\r\n    topHint: true//窗口保持在最前端\r\n    noNotifyIcon: true//隐藏任务栏图标\r\n    modality : Qt.ApplicationModal\r\n    color: \"transparent\"\r\n    width: 360\r\n    height: 200\r\n    property string text\r\n    Component.onCompleted: {\r\n        button_ok.forceActiveFocus()\r\n    }\r\n    Rectangle{\r\n        anchors.fill: parent\r\n        gradient: Gradient {\r\n                        GradientStop { position: 0 ; color:  \"#EEEDEC\" }\r\n                        GradientStop { position: 1 ; color:  \"#f9f9f8\" }\r\n                    }\r\n        radius: 10\r\n        Text{\r\n            id: text\r\n            text: root.text\r\n            anchors.centerIn: parent\r\n            wrapMode :Text.WordWrap//自动换行\r\n            color: \"#f47421\"\r\n            width: parent.width-20\r\n            anchors.bottom: button_ok.top\r\n            anchors.top: parent.top\r\n            anchors.margins: 10\r\n        }\r\n    \r\n        MyButton{\r\n            id: button_ok\r\n            anchors.right: parent.right\r\n            anchors.bottom: parent.bottom\r\n            anchors.margins: 10\r\n            width: 60\r\n            height: 25\r\n            text: \"确认\"\r\n            Keys.onEnterPressed: {\r\n                button_ok.clicked()\r\n            }\r\n            Keys.onReturnPressed: {\r\n                button_ok.clicked()\r\n            }\r\n            onClicked: {\r\n                root.close()\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/MyRectangularGlow.qml",
    "content": "import QtQuick 2.2\r\n\r\nItem{\r\n    id: root\r\n    x: actualX+glowLeftWidth\r\n    y: actualY+glowTopHeight\r\n    property Item item: null\r\n    property int glowTopHeight: (shaderItem.height-rootItem.height)/2-rootItem.y\r\n    property int glowBottomHeight: shaderItem.height-height-glowTopHeight\r\n    property int glowLeftWidth: (shaderItem.height-rootItem.height)/2-rootItem.x\r\n    property int glowRightWidth: shaderItem.width-width-glowLeftWidth\r\n    \r\n    property int actualWidth: glowLeftWidth+width+glowRightWidth\r\n    property int actualHeight: glowTopHeight+height+glowBottomHeight\r\n    \r\n    onItemChanged: {\r\n        item.parent=root\r\n    }\r\n    property real biasX: 0//阴影偏移量\r\n    property real biasY: 0//阴影偏移量\r\n    property alias glowRadius: rootItem.glowRadius\r\n    property alias spread: rootItem.spread\r\n    property alias color: rootItem.color\r\n    property alias cornerRadius: rootItem.cornerRadius\r\n    property alias cached: rootItem.cached\r\n    property alias glowOpacity: rootItem.opacity\r\n    property int actualX: 0//真实的X，算着阴影\r\n    \r\n    onActualXChanged: {\r\n        x = actualX+glowLeftWidth\r\n    }\r\n    property int actualY: 0//真实的Y，算着阴影\r\n    onActualYChanged: {\r\n        y = actualY+glowTopHeight\r\n    }\r\n    onXChanged: {\r\n        actualX = x-glowLeftWidth\r\n    }\r\n    onYChanged: {\r\n        actualY = y-glowTopHeight\r\n    }\r\n\r\n    Item {\r\n        id: rootItem\r\n        property real glowRadius: 0.0\r\n        property real spread: 0.0\r\n        property color color: \"white\"\r\n        property real cornerRadius: glowRadius\r\n        property bool cached: false\r\n\r\n        x: (biasX>0?biasX:0)\r\n        y: (biasY>0?biasY:0)\r\n        width: root.width-biasX\r\n        height: root.height-biasY\r\n\r\n        ShaderEffectSource {\r\n             id: cacheItem\r\n             anchors.fill: shaderItem\r\n             visible: rootItem.cached\r\n             smooth: true\r\n             sourceItem: shaderItem\r\n             live: true\r\n             hideSource: visible\r\n         }\r\n    \r\n        ShaderEffect {\r\n            id: shaderItem\r\n    \r\n            x: (parent.width - width) / 2.0\r\n            y: (parent.height - height) / 2.0\r\n            width: parent.width + rootItem.glowRadius * 2 + cornerRadius * 2\r\n            height: parent.height + rootItem.glowRadius * 2 + cornerRadius * 2\r\n    \r\n            function clampedCornerRadius() {\r\n                var maxCornerRadius = Math.min(rootItem.width, rootItem.height) / 2 + glowRadius;\r\n                return Math.max(0, Math.min(rootItem.cornerRadius, maxCornerRadius))\r\n            }\r\n    \r\n            property color color: rootItem.color\r\n            property real inverseSpread: 1.0 - rootItem.spread\r\n            property real relativeSizeX: ((inverseSpread * inverseSpread) * rootItem.glowRadius + cornerRadius * 2.0) / width\r\n            property real relativeSizeY: relativeSizeX * (width / height)\r\n            property real spread: rootItem.spread / 2.0\r\n            property real cornerRadius: clampedCornerRadius()\r\n    \r\n            fragmentShader: \"\r\n                uniform highp float qt_Opacity;\r\n                uniform mediump float relativeSizeX;\r\n                uniform mediump float relativeSizeY;\r\n                uniform mediump float spread;\r\n                uniform lowp vec4 color;\r\n                varying highp vec2 qt_TexCoord0;\r\n    \r\n                highp float linearstep(highp float e0, highp float e1, highp float x) {\r\n                    return clamp((x - e0) / (e1 - e0), 0.0, 1.0);\r\n                }\r\n    \r\n                void main() {\r\n                    lowp float alpha =\r\n                        smoothstep(0.0, relativeSizeX, 0.5 - abs(0.5 - qt_TexCoord0.x)) *\r\n                        smoothstep(0.0, relativeSizeY, 0.5 - abs(0.5 - qt_TexCoord0.y));\r\n    \r\n                    highp float spreadMultiplier = linearstep(spread, 1.0 - spread, alpha);\r\n                    gl_FragColor = color * qt_Opacity * spreadMultiplier * spreadMultiplier;\r\n                }\r\n            \"\r\n        }\r\n    }    \r\n}\r\n"
  },
  {
    "path": "qml/Utility/MyScrollView.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\n\r\nScrollView{\r\n    id:root\r\n    anchors.fill: parent\r\n    \r\n    style: ScrollViewStyle{\r\n        id: scroll_style\r\n        \r\n        property int hovered_count: 0\r\n        property bool hovered: hovered_count>0\r\n\r\n        handle: Rectangle{\r\n            radius: 10\r\n            implicitWidth: 10\r\n            property bool hovered: styleData.hovered\r\n            onHoveredChanged: {\r\n                if( hovered )\r\n                    scroll_style.hovered_count++\r\n                else\r\n                    scroll_style.hovered_count--\r\n            }\r\n\r\n            color: scroll_style.hovered?\"#808080\":\"#BDBFBE\"\r\n        }\r\n        scrollBarBackground:Rectangle{\r\n            implicitWidth: 10\r\n            color:\"#f0f0f0\"\r\n            radius: 10\r\n            property bool hovered: styleData.hovered\r\n            onHoveredChanged: {\r\n                if( hovered )\r\n                    scroll_style.hovered_count++\r\n                else\r\n                    scroll_style.hovered_count--\r\n            }\r\n            opacity: scroll_style.hovered?1:0\r\n            Behavior on opacity{\r\n                NumberAnimation{\r\n                    duration: 200\r\n                }\r\n            }\r\n        }\r\n        decrementControl : Item{\r\n            implicitHeight: 10\r\n            implicitWidth: 10\r\n            Image{\r\n                source: \"qrc:/images/list_arrow_up.png\"\r\n                property bool hovered: styleData.hovered\r\n                anchors.centerIn: parent\r\n                onHoveredChanged: {\r\n                    if( hovered )\r\n                        scroll_style.hovered_count++\r\n                    else\r\n                        scroll_style.hovered_count--\r\n                }\r\n                opacity: scroll_style.hovered?1:0\r\n                Behavior on opacity{\r\n                    NumberAnimation{\r\n                        duration: 200\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        incrementControl : Item{\r\n            implicitHeight: 10\r\n            implicitWidth: 10\r\n            Image{\r\n                anchors.centerIn: parent\r\n                source: \"qrc:/images/list_arrow_down.png\"\r\n                property bool hovered: styleData.hovered\r\n                onHoveredChanged: {\r\n                    if( hovered )\r\n                        scroll_style.hovered_count++\r\n                    else\r\n                        scroll_style.hovered_count--\r\n                }\r\n                opacity: scroll_style.hovered?1:0\r\n                Behavior on opacity{\r\n                    NumberAnimation{\r\n                        duration: 200\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/MyTextArea.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\nimport QtQuick.Controls.Private 1.0\r\n\r\nScrollView {\r\n    id: area\r\n    \r\n    property alias activeFocusOnPress: edit.activeFocusOnPress\r\n    property alias baseUrl: edit.baseUrl\r\n    readonly property alias canPaste: edit.canPaste\r\n    readonly property alias canRedo: edit.canRedo\r\n    readonly property alias canUndo: edit.canUndo\r\n    property alias textColor: edit.color\r\n    property alias cursorPosition: edit.cursorPosition\r\n    property alias font: edit.font\r\n    property alias horizontalAlignment: edit.horizontalAlignment\r\n    readonly property alias effectiveHorizontalAlignment: edit.effectiveHorizontalAlignment\r\n    property alias verticalAlignment: edit.verticalAlignment\r\n    property alias inputMethodHints: edit.inputMethodHints\r\n    readonly property alias length: edit.length\r\n    readonly property alias lineCount: edit.lineCount\r\n    property alias readOnly: edit.readOnly\r\n    Accessible.readOnly: readOnly\r\n    readonly property alias selectedText: edit.selectedText\r\n    readonly property alias selectionEnd: edit.selectionEnd\r\n    readonly property alias selectionStart: edit.selectionStart\r\n    property bool tabChangesFocus: false\r\n    property alias text: edit.text\r\n    property alias textFormat: edit.textFormat\r\n    property alias wrapMode: edit.wrapMode\r\n    property alias selectByMouse: edit.selectByMouse\r\n    property alias selectByKeyboard: edit.selectByKeyboard\r\n    signal linkActivated(string link)\r\n    signal linkHovered(string link)\r\n    readonly property alias hoveredLink: edit.hoveredLink\r\n    property alias textDocument: edit.textDocument\r\n    default property alias data: area.data\r\n    property alias textMargin: edit.textMargin\r\n    \r\n    frameVisible: true\r\n    activeFocusOnTab: true\r\n    Accessible.role: Accessible.EditableText\r\n    \r\n    function append (string) {\r\n        edit.append(string)\r\n        __verticalScrollBar.value = __verticalScrollBar.maximumValue\r\n    }\r\n\r\n    function copy() {\r\n        edit.copy();\r\n    }\r\n\r\n    function cut() {\r\n        edit.cut();\r\n    }\r\n\r\n    function deselect() {\r\n        edit.deselect();\r\n    }\r\n\r\n    function getFormattedText(start, end) {\r\n        return edit.getFormattedText(start, end);\r\n    }\r\n    \r\n    function getText(start, end) {\r\n        return edit.getText(start, end);\r\n    }\r\n\r\n    function insert(position, text) {\r\n        edit.insert(position, text);\r\n    }\r\n\r\n    function isRightToLeft(start, end) {\r\n        return edit.isRightToLeft(start, end);\r\n    }\r\n\r\n    function moveCursorSelection(position, mode) {\r\n        edit.moveCursorSelection(position, mode);\r\n    }\r\n\r\n    function paste() {\r\n        edit.paste();\r\n    }\r\n\r\n    function positionAt(x, y) {\r\n        return edit.positionAt(x, y);\r\n    }\r\n\r\n    function positionToRectangle(position) {\r\n        return edit.positionToRectangle(position);\r\n    }\r\n\r\n    function redo() {\r\n        edit.redo();\r\n    }\r\n\r\n    function remove(start, end) {\r\n        return edit.remove(start, end);\r\n    }\r\n\r\n    function select(start, end) {\r\n        edit.select(start, end);\r\n    }\r\n\r\n    function selectAll() {\r\n        edit.selectAll();\r\n    }\r\n\r\n    function selectWord() {\r\n        edit.selectWord();\r\n    }\r\n\r\n    function undo() {\r\n        edit.undo();\r\n    }\r\n\r\n    style: ScrollViewStyle {\r\n        id: scroll_style\r\n        //textColor: \"black\"\r\n        frame: Rectangle{\r\n            color: \"#f5f5f5\"\r\n            radius: 5\r\n            border.width: 2\r\n            border.color: \"#ddd\"\r\n        }\r\n        property int hovered_count: 0\r\n        property bool hovered: hovered_count>0\r\n\r\n        handle: Rectangle{\r\n            radius: 10\r\n            implicitWidth: 10\r\n            property bool hovered: styleData.hovered\r\n            onHoveredChanged: {\r\n                if( hovered )\r\n                    scroll_style.hovered_count++\r\n                else\r\n                    scroll_style.hovered_count--\r\n            }\r\n\r\n            color: scroll_style.hovered?\"#808080\":\"#BDBFBE\"\r\n        }\r\n        scrollBarBackground:Rectangle{\r\n            implicitWidth: 10\r\n            color:\"#f0f0f0\"\r\n            radius: 10\r\n            property bool hovered: styleData.hovered\r\n            onHoveredChanged: {\r\n                if( hovered )\r\n                    scroll_style.hovered_count++\r\n                else\r\n                    scroll_style.hovered_count--\r\n            }\r\n            opacity: scroll_style.hovered?1:0\r\n            Behavior on opacity{\r\n                NumberAnimation{\r\n                    duration: 200\r\n                }\r\n            }\r\n        }\r\n        decrementControl : Item{\r\n            implicitHeight: 10\r\n            implicitWidth: 10\r\n            Image{\r\n                source: \"qrc:/images/list_arrow_up.png\"\r\n                property bool hovered: styleData.hovered\r\n                anchors.centerIn: parent\r\n                onHoveredChanged: {\r\n                    if( hovered )\r\n                        scroll_style.hovered_count++\r\n                    else\r\n                        scroll_style.hovered_count--\r\n                }\r\n                opacity: scroll_style.hovered?1:0\r\n                Behavior on opacity{\r\n                    NumberAnimation{\r\n                        duration: 200\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        incrementControl : Item{\r\n            implicitHeight: 10\r\n            implicitWidth: 10\r\n            Image{\r\n                anchors.centerIn: parent\r\n                source: \"qrc:/images/list_arrow_down.png\"\r\n                property bool hovered: styleData.hovered\r\n                onHoveredChanged: {\r\n                    if( hovered )\r\n                        scroll_style.hovered_count++\r\n                    else\r\n                        scroll_style.hovered_count--\r\n                }\r\n                opacity: scroll_style.hovered?1:0\r\n                Behavior on opacity{\r\n                    NumberAnimation{\r\n                        duration: 200\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    Flickable {\r\n        id: flickable\r\n\r\n        interactive: false\r\n        anchors.fill: parent\r\n\r\n        TextEdit {\r\n            id: edit\r\n            focus: true\r\n\r\n            property int layoutRecursionDepth: 0\r\n            textFormat :TextEdit.RichText\r\n            function doLayout() {\r\n                // scrollbars affect the document/viewport size and vice versa, so we\r\n                // must allow the layout loop to recurse twice until the sizes stabilize\r\n                if (layoutRecursionDepth <= 2) {\r\n                    layoutRecursionDepth++\r\n\r\n                    if (wrapMode == TextEdit.NoWrap) {\r\n                        __horizontalScrollBar.visible = edit.contentWidth > viewport.width\r\n                        edit.width = Math.max(viewport.width, edit.contentWidth)\r\n                    } else {\r\n                        __horizontalScrollBar.visible = false\r\n                        edit.width = viewport.width\r\n                    }\r\n                    edit.height = Math.max(viewport.height, edit.contentHeight)\r\n\r\n                    flickable.contentWidth = edit.contentWidth\r\n                    flickable.contentHeight = edit.contentHeight\r\n\r\n                    layoutRecursionDepth--\r\n                }\r\n            }\r\n            \r\n            Connections {\r\n                target: area.viewport\r\n                onWidthChanged: edit.doLayout()\r\n                onHeightChanged: edit.doLayout()\r\n            }\r\n            onContentWidthChanged: edit.doLayout()\r\n            onContentHeightChanged: edit.doLayout()\r\n            onWrapModeChanged: edit.doLayout()\r\n\r\n            renderType: Text.NativeRendering\r\n            font: TextSingleton.font\r\n            color: \"black\"\r\n            selectionColor: \"#888\"\r\n            selectedTextColor: \"white\"\r\n            wrapMode: TextEdit.WordWrap\r\n            textMargin: 4\r\n\r\n            selectByMouse: Qt.platform.os !== \"android\" // Workaround for QTBUG-36515\r\n            readOnly: false\r\n\r\n            Keys.forwardTo: area\r\n\r\n            KeyNavigation.priority: KeyNavigation.BeforeItem\r\n            KeyNavigation.tab: area.tabChangesFocus ? area.KeyNavigation.tab : null\r\n            KeyNavigation.backtab: area.tabChangesFocus ? area.KeyNavigation.backtab : null\r\n\r\n            // keep textcursor within scroll view\r\n            onCursorPositionChanged: {\r\n                if (cursorRectangle.y >= flickableItem.contentY + viewport.height - cursorRectangle.height - textMargin) {\r\n                    // moving down\r\n                    flickableItem.contentY = cursorRectangle.y - viewport.height +  cursorRectangle.height + textMargin\r\n                } else if (cursorRectangle.y < flickableItem.contentY) {\r\n                    // moving up\r\n                    flickableItem.contentY = cursorRectangle.y - textMargin\r\n                }\r\n\r\n                if (cursorRectangle.x >= flickableItem.contentX + viewport.width - textMargin) {\r\n                    // moving right\r\n                    flickableItem.contentX = cursorRectangle.x - viewport.width + textMargin\r\n                } else if (cursorRectangle.x < flickableItem.contentX) {\r\n                    // moving left\r\n                    flickableItem.contentX = cursorRectangle.x - textMargin\r\n                }\r\n            }\r\n            onLinkActivated: area.linkActivated(link)\r\n            onLinkHovered: area.linkHovered(link)\r\n\r\n            MouseArea {\r\n                parent: area.viewport\r\n                anchors.fill: parent\r\n                cursorShape: edit.hoveredLink ? Qt.PointingHandCursor : Qt.IBeamCursor\r\n                acceptedButtons: Qt.NoButton\r\n            }\r\n        }\r\n    }\r\n\r\n    Keys.onPressed: {\r\n        if (event.key == Qt.Key_PageUp) {\r\n            __verticalScrollBar.value -= area.height\r\n        } else if (event.key == Qt.Key_PageDown)\r\n            __verticalScrollBar.value += area.height\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/MyTextField.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Controls 1.2\r\nimport QtQuick.Controls.Styles 1.2\r\n\r\nItem{\r\n    id: root\r\n    property alias title: text.text\r\n    property alias text: input.text\r\n    property alias font: input.font\r\n    property alias field: input\r\n    Text {\r\n        id: text\r\n        anchors.left: parent.left\r\n        anchors.verticalCenter: parent.verticalCenter\r\n        font.pointSize: root.height/2\r\n    }\r\n    TextField{\r\n        id: input\r\n        anchors.left: text.right\r\n        anchors.right: parent.right\r\n        anchors.top: parent.top\r\n        anchors.bottom: parent.bottom\r\n        font.pointSize:text.font.pointSize\r\n        style: TextFieldStyle {\r\n                textColor: \"black\"\r\n                background: BorderImage {\r\n                    source: \"qrc:/images/background_input.png\"\r\n                    border.left: 5; border.top: 5\r\n                    border.right: 5; border.bottom: 5\r\n                }\r\n            }\r\n    }\r\n    Rectangle{\r\n        radius: 1\r\n        anchors.top: input.top\r\n        anchors.topMargin: 2\r\n        anchors.bottom: input.bottom\r\n        anchors.bottomMargin: 0\r\n        anchors.left: input.left\r\n        anchors.leftMargin: 1\r\n        anchors.right: parent.right\r\n        anchors.rightMargin: 1\r\n        \r\n        visible: !root.enabled\r\n        color: \"#f0efef\"\r\n        opacity: 0.75\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/MyTextView.qml",
    "content": "import QtQuick 2.2\r\nimport QtWebKit 3.0\r\n\r\nItem{\r\n    id:root\r\n    property string html: \"\"\r\n    property alias url: webview.url\r\n    \r\n    implicitWidth: webview.contentWidth\r\n    implicitHeight: webview.contentHeight\r\n    onHtmlChanged: {\r\n        webview.loadHtml(html)\r\n    }\r\n    \r\n    WebView{\r\n        id: webview\r\n        anchors.fill: parent\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/MyWindow.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\nimport QtQuick.Window 2.1\r\n\r\nMyQuickWindow{\r\n    id: root\r\n\r\n    property bool removable: true//窗口可移动？\r\n    property bool fixedSize: false//窗口是否固定大小？\r\n    property bool fixedTopBorder: false//固定上边框，上边不可拉动\r\n    property bool fixedBottomBorder: false//同上\r\n    property bool fixedLeftBorder: false//同上\r\n    property bool fixedRightBorder: false//同上\r\n    property var setTopBorder: mySetTopBorder//用鼠标拉动上边框后调用的函数\r\n    property var setBottomBorder: mySetBottomBorder//同上\r\n    property var setLeftBorder: mySetLeftBorder//同上\r\n    property var setRightBorder: mySetRightBorder//同上\r\n    property bool dockableWindow: false//窗口可停靠？\r\n    property bool windowGlow: true//开启窗口阴影？\r\n    property alias windowGlowItem: glow//阴影Item\r\n    property int windowShakeInterval: animation_shake.duration*16///窗口抖动的时间\r\n    property bool centered: true//初次显示时是否居中\r\n    property int contentItemAreaTop: -5//设定内容区域的上边界坐标\r\n    property int contentItemAreaBottom: contentItemAreaTop+height+10//同上\r\n    property int contentItemAreaLeft: -5//同上\r\n    property int contentItemAreaRight: contentItemAreaLeft+width+10//同上\r\n    signal manulPullLeftBorder//如果用户在窗口左边拉动改变了窗口大小\r\n    signal manulPullRightBorder//同上\r\n    signal manulPullTopBorder//同上\r\n    signal manulPullBottomBorder//同上\r\n    \r\n    actualWidth: windowGlow?glow.actualWidth:width+2*mouse_left.width\r\n    actualHeight: windowGlow?glow.actualHeight:height+2*mouse_top.height\r\n\r\n    onContentItemAreaTopChanged: updateMousePenetrateArea()\r\n    onContentItemAreaBottomChanged: updateMousePenetrateArea()\r\n    onContentItemAreaLeftChanged: updateMousePenetrateArea()\r\n    onContentItemAreaRightChanged: updateMousePenetrateArea()\r\n\r\n    Component.onCompleted: {\r\n        if(centered){\r\n            var old_visible = visible\r\n            visible = false\r\n            actualX = Screen.desktopAvailableWidth/2 - actualWidth/2\r\n            actualY = Screen.desktopAvailableHeight/2 - actualHeight/2\r\n            visible = old_visible\r\n        }\r\n    }\r\n\r\n    contentItem{\r\n        x: windowGlow?glow.glowLeftWidth:mouse_left.width\r\n        y: windowGlow?glow.glowTopHeight:mouse_top.height\r\n    }\r\n\r\n    Connections{\r\n        target: windowGlow?contentItem:null\r\n        onWidthChanged:{\r\n            contentItem.width=width\r\n        }\r\n        onHeightChanged:{\r\n            contentItem.height=height\r\n        }\r\n    }\r\n\r\n    QtObject{\r\n        id: obj\r\n        property int windowShakeCount: 0\r\n        property real back_glowOpacity\r\n        Component.onCompleted: {\r\n            back_glowOpacity = glow.glowOpacity\r\n        }\r\n    }\r\n\r\n    function updateMousePenetrateArea(){\r\n        var rect = Qt.rect(contentItemAreaLeft, contentItemAreaTop, 0, 0)\r\n        rect.width = contentItemAreaRight - rect.x + 1\r\n        rect.height = contentItemAreaBottom - rect.y + 1\r\n        setMousePenetrateArea(rect)\r\n    }\r\n\r\n    function windowShake() {//抖动窗口\r\n        if(obj.windowShakeCount>=root.windowShakeInterval/animation_shake.duration/4){\r\n            obj.windowShakeCount=0\r\n            return\r\n        }\r\n\r\n        ++obj.windowShakeCount\r\n        showFront()//先把窗口显示在最前端\r\n        animation_shake.property = \"x\"\r\n        animation_shake.to = root.x-20\r\n        animation_shake.backFun=function(){\r\n            animation_shake.property = \"y\"\r\n            animation_shake.to = root.y-20\r\n            animation_shake.backFun=function(){\r\n                animation_shake.property=\"x\"\r\n                animation_shake.to=root.x+20\r\n                animation_shake.backFun=function(){\r\n                    animation_shake.property=\"y\"\r\n                    animation_shake.to=root.y+20\r\n                    animation_shake.backFun=function(){\r\n                        windowShake()//进行递归调用\r\n                    }\r\n                    animation_shake.start()\r\n                }\r\n                animation_shake.start()\r\n            }\r\n            animation_shake.start()\r\n        }\r\n        animation_shake.start()\r\n    }\r\n    function showFront() {//显示到最前面\r\n        if(root.visible) {\r\n            if( root.visibility== MyQuickWindow.Minimized){\r\n                root.show()\r\n            }\r\n            root.requestActivate()//让窗体显示到最前端\r\n        }\r\n    }\r\n\r\n    function berthWindow(){\r\n        if( root.windowStatus!=MyQuickWindow.BerthPrepare||animation.running ) {//如果不是准停状态\r\n            return\r\n        }\r\n        if( root.x==root.borderLeft ){\r\n            root.windowStatus = MyQuickWindow.BerthLeft\r\n            animation.property = \"x\"\r\n            animation.to = root.borderLeft-width+1\r\n            animation.start()\r\n        }else if( root.x==root.borderRight-root.width ){\r\n            root.windowStatus = MyQuickWindow.BerthRight\r\n            animation.property = \"x\"\r\n            animation.to = root.borderRight-1\r\n            animation.start()\r\n        }else if( root.y==root.borderTop ){\r\n            root.windowStatus = MyQuickWindow.BerthTop\r\n            animation.property = \"y\"\r\n            animation.to = root.borderTop-height+1\r\n            animation.start()\r\n        }\r\n    }\r\n    \r\n    function showWindow(){///从停靠状态转为可停靠状态\r\n        if( animation.running ) {//如果动画正在运行\r\n            return\r\n        }\r\n        switch( windowStatus ){\r\n        case MyQuickWindow.BerthTop:\r\n        {\r\n            animation.property = \"y\"\r\n            animation.to = root.borderTop\r\n            animation.start()\r\n            root.windowStatus = MyQuickWindow.BerthPrepare//进入准停靠状态\r\n            break;\r\n        }\r\n        case MyQuickWindow.BerthLeft:\r\n        {\r\n            animation.property = \"x\"\r\n            animation.to = root.borderLeft\r\n            animation.start()\r\n            root.windowStatus = MyQuickWindow.BerthPrepare//进入准停靠状态\r\n            break;\r\n        }\r\n        case MyQuickWindow.BerthRight:\r\n        {\r\n            animation.property = \"x\"\r\n            animation.to = root.borderRight-root.width\r\n            animation.start()\r\n            root.windowStatus = MyQuickWindow.BerthPrepare//进入准停靠状态\r\n            break;\r\n        }\r\n        default:break\r\n        }\r\n    }\r\n    function mySetLeftBorder(arg){//当从左边改变窗口的width时\r\n        if(!fixedLeftBorder){\r\n            var temp = root.width\r\n            root.width+=arg;\r\n            temp = root.width-temp//计算出其中的差值\r\n            if(temp!=0){\r\n                root.x-=temp//改变窗口坐标\r\n                manulPullLeftBorder()//发送拉动了左边界的信号\r\n            }\r\n        }\r\n    }\r\n    function mySetRightBorder(arg){//当从右边改变窗口的width时\r\n        if(!fixedRightBorder){\r\n            var temp = root.width\r\n            root.width+=arg;\r\n            temp = root.width-temp//计算出其中的差值\r\n            if(temp!=0){\r\n                manulPullRightBorder()//发送拉动了右边界的信号\r\n            }\r\n        }\r\n    }\r\n    function mySetTopBorder(arg){//当从上边改变窗口的width时\r\n        if(!fixedTopBorder){\r\n            var temp = root.height\r\n            root.height+=arg;\r\n            temp = root.height-temp//计算出其中的差值\r\n            if(temp!=0){\r\n                root.y-=temp//改变窗口坐标\r\n                manulPullTopBorder()//发送拉动了上边界的信号\r\n            }\r\n        }\r\n    }\r\n    function mySetBottomBorder(arg){//当从下边改变窗口的width时\r\n        if(!fixedBottomBorder){\r\n            var temp = root.height\r\n            root.height+=arg;\r\n            temp = root.height-temp//计算出其中的差值\r\n            if(temp!=0){\r\n                manulPullBottomBorder()//发送拉动了下边界的信号\r\n            }\r\n        }\r\n    }\r\n\r\n    NumberAnimation{\r\n        id: animation\r\n        target: root\r\n        duration: 100\r\n    }\r\n    NumberAnimation{\r\n        id: animation_shake\r\n        target: root\r\n        duration: 50\r\n        easing.type: Easing.OutInElastic\r\n        property var backFun: null\r\n        onStopped: {\r\n            if(backFun)\r\n                backFun()\r\n        }\r\n    }\r\n    NumberAnimation{\r\n        id: animation_shake_x\r\n        target: root\r\n        duration: 100\r\n        property: \"x\"\r\n        easing.type: Easing.OutInElastic\r\n        property var backFun: null\r\n        onStopped: {\r\n            if(backFun)\r\n                backFun()\r\n        }\r\n    }\r\n    NumberAnimation{\r\n        id: animation_shake_y\r\n        target: root\r\n        duration: 100\r\n        property: \"y\"\r\n        easing.type: Easing.OutInElastic\r\n        property var backFun: null\r\n        onStopped: {\r\n            if(backFun)\r\n                backFun()\r\n        }\r\n    }\r\n    \r\n    MyRectangularGlow{\r\n        id: glow\r\n        visible: windowGlow&&root.windowActive\r\n        x:0\r\n        y:0\r\n        glowRadius: 50\r\n        glowOpacity: 0.75\r\n        biasY: 20\r\n        spread: 0.1\r\n        color: \"black\"\r\n        width: root.width\r\n        height:root.height\r\n    }\r\n    \r\n    MyRectangularGlow{\r\n        id: glow_inactive//当窗口处于非活跃状态时显示的阴影\r\n        anchors.fill: glow\r\n        glowRadius: glow.glowRadius/2\r\n        spread: glow.spread\r\n        color: glow.color\r\n        glowOpacity: glow.glowOpacity\r\n        cornerRadius: glow.cornerRadius\r\n        biasX: glow.biasX\r\n        biasY: glow.biasY\r\n        cached: glow.cached\r\n        visible: windowGlow&&(!root.windowActive)\r\n    }\r\n    \r\n    MouseArea{\r\n        id: mouse_main\r\n\r\n        property real pressedX: 0\r\n        property real pressedY: 0\r\n        property point pressedCursorPos\r\n\r\n        enabled: removable\r\n        anchors.fill: parent\r\n        hoverEnabled: dockableWindow\r\n        \r\n        onPressed: {\r\n            pressedX = root.x\r\n            pressedY = root.y\r\n            pressedCursorPos = cursorPos\r\n        }\r\n        onEntered: {\r\n            if(dockableWindow){\r\n                showWindow()//将窗口从停靠地方显示出来\r\n            }\r\n        }\r\n\r\n        onExited: {\r\n            if(dockableWindow){//如果开启了窗口停靠\r\n                mouse_main_connections.target = root//接收全局鼠标改变的信号\r\n            }\r\n        }\r\n\r\n        onReleased: {\r\n            if(dockableWindow&&(!animation.running)&&(root.windowStatus==MyQuickWindow.StopCenter||root.windowStatus==MyQuickWindow.BerthPrepare)){\r\n                if( root.x<=root.borderLeft ){\r\n                    root.x=root.borderLeft\r\n                    root.windowStatus = MyQuickWindow.BerthPrepare//进入准停靠状态\r\n                }else if( root.x>root.borderRight-root.width ){\r\n                    root.x = root.borderRight-root.width\r\n                    root.windowStatus = MyQuickWindow.BerthPrepare//进入准停靠状态\r\n                }else if( root.y<root.borderTop ){\r\n                    root.y = root.borderTop\r\n                    root.windowStatus = MyQuickWindow.BerthPrepare//进入准停靠状态\r\n                }else if( root.windowStatus == MyQuickWindow.BerthPrepare )\r\n                    root.windowStatus = MyQuickWindow.StopCenter//失去准停靠状态\r\n            }\r\n        }\r\n\r\n        onPositionChanged: {\r\n            if( mouse_main.pressed ){//如果鼠标被按下\r\n                root.x = (cursorPos.x - pressedCursorPos.x + pressedX)//改变窗口的位置\r\n                root.y = (cursorPos.y - pressedCursorPos.y + pressedY)//改变窗口的位置\r\n            }else{\r\n                var x = arg.x-root.x\r\n                var y = arg.y-root.y\r\n                if(!(x<=contentItemAreaRight&&x>=contentItemAreaLeft\r\n                     &&y<=contentItemAreaBottom&&y>=contentItemAreaTop)){\r\n                    berthWindow()//调用函数让窗口进行停靠\r\n                    mouse_main_connections.target = null//关闭接收全局鼠标改变的信号\r\n                }\r\n            }\r\n        }\r\n    }\r\n    MouseArea{//接收窗口上部的鼠标事件，用于朝上拉动窗口来改变窗口的大小\r\n        id: mouse_top\r\n        enabled: noBorder&&!fixedSize&&!fixedTopBorder&&root.windowStatus==MyQuickWindow.StopCenter\r\n        cursorShape :enabled?Qt.SizeVerCursor:Qt.ArrowCursor//鼠标样式\r\n        anchors.bottom: parent.top\r\n        anchors.horizontalCenter: parent.horizontalCenter\r\n        width: root.width-6\r\n        height: 3\r\n        z:1\r\n        property real pressedX: 0\r\n        property real pressedY: 0\r\n        onPressed: {\r\n            pressedX = mouseX\r\n            pressedY = mouseY\r\n        }\r\n        onPositionChanged: {\r\n            var num_temp = pressedY-mouseY\r\n            setTopBorder(num_temp)\r\n        }\r\n    }\r\n    MouseArea{//接收窗口下部的鼠标事件，用于朝下拉动窗口来改变窗口的大小\r\n        id: mouse_bottom\r\n        enabled: noBorder&&!fixedSize&&!fixedBottomBorder&&root.windowStatus==MyQuickWindow.StopCenter\r\n        cursorShape :enabled?Qt.SizeVerCursor:Qt.ArrowCursor\r\n        anchors.top: parent.bottom\r\n        anchors.horizontalCenter: parent.horizontalCenter\r\n        width: root.width-6\r\n        height: 3\r\n        z:1\r\n        property real pressedX: 0\r\n        property real pressedY: 0\r\n        onPressed: {\r\n            pressedY = mouseY\r\n        }\r\n        onPositionChanged: {\r\n            var num_temp = mouseY-pressedY\r\n            setBottomBorder(num_temp)\r\n        }\r\n    }\r\n    MouseArea{//接收窗口左部的鼠标事件，用于朝左拉动窗口来改变窗口的大小\r\n        id: mouse_left\r\n        enabled: noBorder&&!fixedSize&&!fixedLeftBorder&&root.windowStatus==MyQuickWindow.StopCenter\r\n        cursorShape :enabled?Qt.SizeHorCursor:Qt.ArrowCursor\r\n        anchors.right: parent.left\r\n        anchors.verticalCenter: parent.verticalCenter\r\n        height: root.height-6\r\n        width: 3\r\n        z:1\r\n        property real pressedX: 0\r\n        property real pressedY: 0\r\n\r\n        onPressed: {\r\n            pressedX = mouseX\r\n        }\r\n        onPositionChanged: {\r\n            var num_temp = pressedX-mouseX\r\n            setLeftBorder(num_temp)\r\n        }\r\n    }\r\n    MouseArea{//接收窗口右部的鼠标事件，用于朝右拉动窗口来改变窗口的大小\r\n        id: mouse_right\r\n        enabled: noBorder&&!fixedSize&&!fixedRightBorder&&root.windowStatus==MyQuickWindow.StopCenter\r\n        cursorShape :enabled?Qt.SizeHorCursor:Qt.ArrowCursor\r\n        anchors.left: parent.right\r\n        anchors.verticalCenter: parent.verticalCenter\r\n        height: root.height-6\r\n        width: 3\r\n        z:1\r\n        property real pressedX: 0\r\n        property real pressedY: 0\r\n        onPressed: {\r\n            pressedX = mouseX\r\n        }\r\n        onPositionChanged: {\r\n            var num_temp = mouseX-pressedX\r\n            setRightBorder(num_temp)\r\n        }\r\n    }\r\n    MouseArea{//接收窗口左上部的鼠标事件，用于朝左拉动窗口来改变窗口的大小\r\n        enabled: mouse_left.enabled&&mouse_top.enabled\r\n        cursorShape :enabled?Qt.SizeFDiagCursor:Qt.ArrowCursor\r\n        anchors.right: parent.left\r\n        anchors.bottom: parent.top\r\n        height: 5\r\n        width: 5\r\n        z:1\r\n        property real pressedX: 0\r\n        property real pressedY: 0\r\n        onPressed: {\r\n            pressedX = mouseX\r\n            pressedY = mouseY\r\n        }\r\n        onPositionChanged: {\r\n            var num_temp1 = pressedX-mouseX\r\n            setLeftBorder(num_temp1)\r\n            var num_temp2 = pressedY-mouseY\r\n            setTopBorder(num_temp2)\r\n        }\r\n    }\r\n    MouseArea{//接收窗口右上部的鼠标事件，用于朝左拉动窗口来改变窗口的大小\r\n        enabled: mouse_right.enabled&&mouse_top.enabled\r\n        cursorShape :enabled?Qt.SizeBDiagCursor:Qt.ArrowCursor\r\n        anchors.left: parent.right\r\n        anchors.bottom: parent.top\r\n        height: 5\r\n        width: 5\r\n        z:1\r\n        property real pressedX: 0\r\n        property real pressedY: 0\r\n        onPressed: {\r\n            pressedX = mouseX\r\n            pressedY = mouseY\r\n        }\r\n        onPositionChanged: {\r\n            var num_temp1 = mouseX-pressedX\r\n            setRightBorder(num_temp1)\r\n            var num_temp2 = pressedY-mouseY\r\n            setTopBorder(num_temp2)\r\n        }\r\n    }\r\n    MouseArea{//接收窗口左下部的鼠标事件，用于朝左拉动窗口来改变窗口的大小\r\n        enabled:mouse_left.enabled&&mouse_bottom.enabled\r\n        cursorShape :enabled?Qt.SizeBDiagCursor:Qt.ArrowCursor\r\n        anchors.right: parent.left\r\n        anchors.top: parent.bottom\r\n        height: 5\r\n        width: 5\r\n        z:1\r\n        property real pressedX: 0\r\n        property real pressedY: 0\r\n        onPressed: {\r\n            pressedX = mouseX\r\n            pressedY = mouseY\r\n        }\r\n        onPositionChanged: {\r\n            var num_temp1 = pressedX-mouseX\r\n            setLeftBorder(num_temp1)\r\n            var num_temp2 = mouseY-pressedY\r\n            setBottomBorder(num_temp2)\r\n        }\r\n    }\r\n    MouseArea{//接收窗口右下部的鼠标事件，用于朝左拉动窗口来改变窗口的大小\r\n        enabled: mouse_right.enabled&&mouse_bottom.enabled\r\n        cursorShape :enabled?Qt.SizeFDiagCursor:Qt.ArrowCursor\r\n        anchors.left: parent.right\r\n        anchors.top: parent.bottom\r\n        height: 5\r\n        width: 5\r\n        z:1\r\n        property real pressedX: 0\r\n        property real pressedY: 0\r\n        onPressed: {\r\n            pressedX = mouseX\r\n            pressedY = mouseY\r\n        }\r\n        onPositionChanged: {\r\n            var num_temp1 = mouseX-pressedX\r\n            setRightBorder(num_temp1)\r\n            var num_temp2 = mouseY-pressedY\r\n            setBottomBorder(num_temp2)\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/SystemTray.qml",
    "content": "import QtQuick 2.2\r\nimport mywindow 1.0\r\nimport utility 1.0\r\nimport QQItemInfo 1.0\r\nimport qqstars 1.0\r\n\r\nMySystemTrayIcon{\r\n    id: root\r\n    property QQItemInfo currentInfo//当前最新消息的发送人的信息\r\n    property bool hovered: false//鼠标是否悬浮在托盘上空\r\n    property TrayMessageWindow trayMessageWindow\r\n    signal triggered(var arg)\r\n    \r\n\r\n    visible: true\r\n    windowIcon: \"qrc:/images/avatar.png\"\r\n    menu: myqq.loginStatus == QQ.LoginFinished?menu2:menu1\r\n    \r\n    toolTip: {\r\n        if( myqq.loginStatus == QQ.LoginFinished ){\r\n            return \"QQ:\"+myqq.nick+\"(\"+myqq.userQQ+\")\"\r\n        }else\r\n            return \"星辰QQ\"\r\n    }\r\n    \r\n    function iconShakeStart(){//开启图标闪动\r\n        windowIcon = currentInfo.avatar40//设置图标\r\n        timer_shake.start()\r\n        console.log(\"开启了头像闪动\")\r\n    }\r\n    function iconShakeStop(){//停止鼠标闪动\r\n        timer_shake.stop()\r\n        windowIcon = \"qrc:/images/avatar.png\"\r\n    }\r\n    \r\n    onCurrentInfoChanged: {\r\n        if(timer_shake.running)\r\n            windowIcon = currentInfo.avatar40//设置图标\r\n    }\r\n    Connections{\r\n        target: timer_shake.running?currentInfo:null\r\n        onAvatar40Changed:{\r\n            windowIcon = currentInfo.avatar40//设置图标\r\n        }\r\n    }\r\n\r\n    Component.onCompleted: {\r\n        var component = Qt.createComponent(\"TrayMessageWindow.qml\");\r\n        if (component.status == Component.Ready){\r\n            trayMessageWindow = component.createObject(null, {});\r\n        }\r\n    }\r\n    \r\n    onMessageClicked:{\r\n        iconShakeStop()//停止闪动头像\r\n        myqq.addChatPage(currentInfo.uin, currentInfo.mytype)//增加聊天页面\r\n    }\r\n    onActivated:{\r\n        if( timer_shake.running&&arg == MySystemTrayIcon.Trigger ) {//如果头像正在闪动\r\n            iconShakeStop()//停止闪动头像\r\n            myqq.addChatPage(currentInfo.uin, currentInfo.mytype)//增加聊天页面\r\n        }\r\n    }\r\n    Connections{\r\n        target: trayMessageWindow\r\n        onStopShakeIcon: {//如果清除全部消息提示\r\n            iconShakeStop()//停止闪动头像\r\n        }\r\n        onSetCurrentInfo:{\r\n            currentInfo = info\r\n        }\r\n    }\r\n\r\n    Connections{\r\n        target: timer_shake.running?utility:null\r\n        onMouseDesktopPosChanged:{\r\n            if(arg.x>=root.x&&arg.y>=root.y&&arg.x<=root.x+root.width&&arg.y<=root.y+root.height){\r\n                if(!hovered){\r\n                    hovered = true\r\n                    //console.debug(\"进入了托盘区域\")\r\n                    root.toolTip = \"\"\r\n                    trayMessageWindow.showWindow(root.x, root.y, root.width, root.height)//显示消息通知框\r\n                }\r\n            }else if(hovered){\r\n                hovered = false\r\n                trayMessageWindow.closeWindow()//隐藏消息通知栏\r\n                root.toolTip = \"QQ:\"+myqq.nick+\"(\"+myqq.userQQ+\")\"\r\n            }\r\n        }\r\n    }\r\n\r\n    Connections{\r\n        target: myqq\r\n        onNewMessage:{\r\n            if(!myqq.isChatPageExist(fromUin, type)){//判断聊天页面是否存在，如果存在的话 不用提示新消息\r\n                console.debug(\"收到了新的未读消息：\"+currentInfo)\r\n                if(type==QQItemInfo.Friend){//如果是qq消息\r\n                    currentInfo = myqq.createFriendInfo(fromUin)\r\n                }else if(type==QQItemInfo.Group){//如果是群消息\r\n                    currentInfo = myqq.createGroupInfo(fromUin)\r\n                }else if(type==QQItemInfo.Discu){//如果是讨论组消息\r\n                    currentInfo = myqq.createDiscuInfo(fromUin)\r\n                }\r\n                trayMessageWindow.appendModel(currentInfo)\r\n                iconShakeStart()//开始闪动\r\n            }\r\n        }\r\n    }\r\n    \r\n    Timer{\r\n        id: timer_shake\r\n        interval: 300\r\n        repeat: true//开启重复闪动\r\n        property string old_icon\r\n        onTriggered: {\r\n            if(root.windowIcon!=\"\"){\r\n                old_icon=root.windowIcon\r\n                root.windowIcon=\"\"\r\n            }else{\r\n                root.windowIcon=old_icon\r\n            }\r\n        }\r\n    }\r\n\r\n    MyMenu{\r\n        id:menu1\r\n        styleSource: \"qrc:/style/menuStyle.css\"\r\n        MyMenuItem{\r\n            text: \"打开主面板\"\r\n            onTriggered: {\r\n                root.triggered(text)\r\n            }\r\n        }\r\n        MyMenuItem{\r\n            text: \"退出\"\r\n            onTriggered: Qt.quit()\r\n        }\r\n    }\r\n    \r\n    MyMenu{\r\n        id: menu2\r\n\r\n        styleSource: \"qrc:/style/menuStyle.css\"\r\n        MyMenuItem{\r\n            text: \"我在线上\"\r\n            icon: \"qrc:/images/imonline.png\"\r\n            onTriggered: {\r\n                myqq.state = QQ.Online\r\n            }\r\n        }\r\n        MyMenuItem{\r\n            text: \"Q我吧\"\r\n            icon: \"qrc:/images/imcallme.png\"\r\n            onTriggered: {\r\n                myqq.state = QQ.Callme\r\n            }\r\n        }\r\n        MyMenuItem{\r\n            text: \"离开\"\r\n            icon: \"qrc:/images/imaway.png\"\r\n            onTriggered: {\r\n                myqq.state = QQ.Away\r\n            }\r\n        }\r\n        MyMenuItem{\r\n            text: \"忙碌\"\r\n            icon: \"qrc:/images/imbusy.png\"\r\n            onTriggered: {\r\n                myqq.state = QQ.Busy\r\n            }\r\n        }\r\n        MyMenuItem{\r\n            text: \"请勿打扰\"\r\n            icon: \"qrc:/images/imsilent.png\"\r\n            onTriggered: {\r\n                myqq.state = QQ.Silent\r\n            }\r\n        }\r\n        MyMenuItem{\r\n            text: \"隐身\"\r\n            icon: \"qrc:/images/imhidden.png\"\r\n            onTriggered: {\r\n                myqq.state = QQ.Hidden\r\n            }\r\n        }\r\n        MyMenuItem{\r\n            text: \"离线\"\r\n            icon: \"qrc:/images/imoffline.png\"\r\n            onTriggered: {\r\n                myqq.state = QQ.Offline\r\n            }\r\n        }\r\n        MenuSeparator{}\r\n        MyMenuItem{\r\n            text: \"关闭所有声音\"\r\n        }\r\n        MyMenuItem{\r\n            text: \"关闭头像闪动\"\r\n        }\r\n        MenuSeparator{}\r\n        MyMenuItem{\r\n            text: lock_qq?\"解锁QQ\":\"锁定QQ\"\r\n            shortcut: \"Ctrl+Alt+L\"\r\n            property bool lock_qq: false\r\n            icon: lock_qq?\"qrc:/images/unlock20.png\":\"qrc:/images/lock20.png\"\r\n            onTriggered: {\r\n                lock_qq = !lock_qq\r\n            }\r\n        }\r\n        MenuSeparator{}\r\n        MyMenuItem{\r\n            text: \"打开主面板\"\r\n            onTriggered: {\r\n                root.triggered(text)\r\n            }\r\n        }\r\n        MenuSeparator{}\r\n        MyMenuItem{\r\n            text: \"&退出\"\r\n            onTriggered: {\r\n                Qt.quit()\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml/Utility/TrayMessageWindow.qml",
    "content": "import QtQuick 2.2\r\nimport QtQuick.Window 2.0\r\nimport mywindow 1.0\r\n//import \"../QQItemInfo\"\r\n\r\nWindow{\r\n    id: root\r\n    flags: Qt.SplashScreen|Qt.WindowStaysOnTopHint\r\n    height: list.height+user_nick.implicitHeight+item_button.height+30\r\n    width: 200\r\n    color: \"transparent\"\r\n    signal stopShakeIcon//停止对托盘图标的闪动\r\n    signal setCurrentInfo(var info)\r\n    property var infosQueue: new Array\r\n    \r\n    function appendModel(senderInfo){\r\n        for(var i in infosQueue){\r\n            if(infosQueue[i] == senderInfo){//如果对象已经存在\r\n                return\r\n            }\r\n        }\r\n        mymodel.append({\"sender_info\": senderInfo})\r\n        infosQueue.push(senderInfo)//加到队列里边\r\n    }\r\n    function removeModel(index){\r\n        if(index>=0){\r\n            mymodel.remove(index)\r\n            infosQueue.splice(index, 1)\r\n            //console.debug(mymodel.count+\",\"+infosQueue.length)\r\n            if(mymodel.count==0)\r\n                stopShakeIcon()//停止闪动\r\n        }\r\n    }\r\n    function clearModel(){\r\n        stopShakeIcon()//发送信号\r\n        mymodel.clear()\r\n        infosQueue.length=0\r\n    }\r\n    function getLatestInfo(){\r\n        if(infosQueue.length>0)\r\n            return infosQueue[infosQueue.length-1]\r\n        else\r\n            return null\r\n    }\r\n    function showWindow(trayX, trayY, trayWidth, trayHeight){\r\n        timer_close.stop()//先停止动画\r\n        root.opacity = 1\r\n        root.show()\r\n        var tempx = trayX-width/2+trayWidth/2\r\n        if(tempx<0)\r\n            x=trayX+trayWidth\r\n        else if(tempx+width>Screen.desktopAvailableWidth)\r\n            x=trayX-width\r\n        else\r\n            x=tempx\r\n        var tempy = trayY-height/2+trayHeight/2\r\n        if(tempy<0)\r\n            y=trayY+trayHeight\r\n        else if(tempy+height>Screen.desktopAvailableHeight)\r\n            y=trayY-height\r\n        else\r\n            y=tempy\r\n    }\r\n    function closeWindow(){\r\n        if(!mouse_area.hovered)//如果当前鼠标没有在自己区域\r\n            timer_close.start()//启动动画定时器\r\n    }\r\n    NumberAnimation{\r\n        id: timer_close\r\n        target: root\r\n        property: \"opacity\"\r\n        running: false\r\n        duration: 800\r\n        from: 1\r\n        to: 0\r\n        onStopped: {//当动画结束后\r\n            if(root.opacity==0){\r\n                root.close()\r\n            }\r\n        }\r\n    }\r\n\r\n    MouseArea{\r\n        id: mouse_area\r\n        anchors.fill: parent\r\n        property bool hovered: false\r\n        hoverEnabled: true\r\n        onEntered: {\r\n            hovered = true\r\n            timer_close.stop()//停止关闭窗口的动画\r\n            root.opacity = 1\r\n            //console.debug(\"进入了区域\")\r\n        }\r\n        onExited: {\r\n            var globalX = utility.mouseDesktopPos().x\r\n            var globalY = utility.mouseDesktopPos().y\r\n            //console.log(\"x:\"+root.x+\",\"+width+\",\"+globalX)\r\n            //console.log(\"y:\"+root.y+\",\"+height+\",\"+globalY)\r\n            if(globalX<root.x||globalX>root.x+root.width||globalY<root.y||globalY>root.y+root.height){\r\n                hovered = false\r\n                root.closeWindow()\r\n                //console.debug(\"离开了区域\")\r\n            }\r\n        }\r\n    }\r\n    Rectangle{\r\n        width: parent.width\r\n        height: list.height+user_nick.implicitHeight+item_button.height+30\r\n        border.width: 1\r\n        border.color: \"#f07000\"\r\n        color: \"white\"\r\n        radius: 10\r\n        Text{\r\n            id: user_nick\r\n            text: myqq.nick\r\n            x:10\r\n            y:10\r\n        }\r\n\r\n        ListView{\r\n            id:list\r\n            delegate: list_delegate\r\n            anchors.left: parent.left\r\n            anchors.right: parent.right\r\n            anchors.top: user_nick.bottom\r\n            height: mymodel.count*40\r\n            \r\n            clip: true\r\n            anchors.margins: 10\r\n            signal openAllChatPage//当点击\"查看全部\"时被发射\r\n            model: ListModel{\r\n                id:mymodel\r\n            }\r\n        }\r\n        \r\n        Item{\r\n            id: item_button\r\n            anchors.top: list.bottom\r\n            anchors.topMargin: 10\r\n            anchors.left: list.left\r\n            anchors.right: list.right\r\n            height: 30\r\n            Rectangle{\r\n                width: parent.width\r\n                height: 1\r\n                color: \"#f07000\"\r\n            }\r\n\r\n            Text{\r\n                text: \"忽略全部\"\r\n                color: \"#f07000\"\r\n                font.underline: true\r\n                anchors.verticalCenter: parent.verticalCenter\r\n                MouseArea{\r\n                    anchors.fill: parent\r\n                    onClicked: {\r\n                        clearModel()//先清除所有数据\r\n                        root.close()//然后关闭窗口\r\n                    }\r\n                }\r\n            }\r\n            Text{\r\n                text: \"查看全部\"\r\n                color: \"#f07000\"\r\n                font.underline: true\r\n                anchors.verticalCenter: parent.verticalCenter\r\n                anchors.right: parent.right\r\n                MouseArea{\r\n                    anchors.fill: parent\r\n                    onClicked: {\r\n                        list.openAllChatPage()//发送信号\r\n                        clearModel()//先清除所有数据\r\n                        root.close()//然后关闭窗口\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n    Component{\r\n        id: list_delegate\r\n        Item{\r\n            id: myitem\r\n            width: parent.width\r\n            height: 40\r\n            property var myinfo: sender_info\r\n            function removeMe(){\r\n                root.close()//关闭窗口\r\n                removeModel(index)//清除自己\r\n                var temp_info = getLatestInfo()\r\n                if(temp_info!=null){\r\n                    setCurrentInfo(temp_info)\r\n                }\r\n            }\r\n\r\n            Connections{\r\n                target: list\r\n                onOpenAllChatPage: {\r\n                    myqq.addChatPage(myinfo.uin, myinfo.mytype)\r\n                }\r\n            }\r\n            \r\n            Rectangle{\r\n                anchors.fill: parent\r\n                color: \"#aaa\"\r\n                opacity: 0.8\r\n                visible: item_mouse.hovered\r\n            }\r\n\r\n            MyImage{\r\n                id: avatar\r\n                x:10\r\n                width:parent.height-10\r\n                height: width\r\n                sourceSize.width: width\r\n                anchors.verticalCenter: parent.verticalCenter\r\n                maskSource: \"qrc:/images/bit.bmp\"\r\n                cache: false\r\n                source: myinfo.avatar40\r\n            }\r\n            Text{\r\n                id: nick\r\n                anchors.left: avatar.right\r\n                anchors.leftMargin: 10\r\n                anchors.top: avatar.top\r\n                text: myinfo.aliasOrNick\r\n            }\r\n            Rectangle{\r\n                width: text_message_count.implicitWidth+10\r\n                height: text_message_count.implicitHeight+10\r\n                anchors.verticalCenter: parent.verticalCenter\r\n                anchors.right: parent.right\r\n                anchors.rightMargin: 5\r\n                color: \"red\"\r\n                opacity: 0.75\r\n                radius: height\r\n                Text{\r\n                    id: text_message_count\r\n                    anchors.centerIn: parent\r\n                    text: myinfo.unreadMessagesCount//未读消息的个数\r\n                    color: \"white\"\r\n                    onTextChanged: {\r\n                        if(text == \"100\"){\r\n                            text = \"99+\"\r\n                        }else if(text == \"0\"){//如果未读消息个数变为0\r\n                            myitem.removeMe()//移除自己\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            MouseArea{\r\n                id: item_mouse\r\n                anchors.fill: parent\r\n                property bool hovered: false\r\n                hoverEnabled: true\r\n                onEntered: {\r\n                    hovered = true\r\n                }\r\n                onExited: {\r\n                    hovered = false\r\n                }\r\n                onClicked: {\r\n                    myqq.addChatPage(myinfo.uin, myinfo.mytype)//点击了之后开始聊天\r\n                    myitem.removeMe()//移除自己\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "qml.qrc",
    "content": "<RCC>\r\n    <qresource prefix=\"/\">\r\n        <file>qml/QQItemInfo/DiscuInfo.qml</file>\r\n        <file>qml/QQItemInfo/FriendInfo.qml</file>\r\n        <file>qml/QQItemInfo/GroupInfo.qml</file>\r\n        <file>qml/Api/api.js</file>\r\n        <file>qml/Api/QQApi.qml</file>\r\n        <file>qml/Chat/ChatPage.qml</file>\r\n        <file>qml/Chat/ChatWindowCommand.qml</file>\r\n        <file>qml/Chat/DiscuChatPage.qml</file>\r\n        <file>qml/Chat/FriendChatPage.qml</file>\r\n        <file>qml/Chat/GroupChatPage.qml</file>\r\n        <file>qml/Chat/MessageListComponent.qml</file>\r\n        <file>qml/Chat/qqshow.png</file>\r\n        <file>qml/Login/LoginPanel/AccountList.qml</file>\r\n        <file>qml/Login/LoginPanel/LoginCheckBox.qml</file>\r\n        <file>qml/Login/LoginPanel/LoginInputArea.qml</file>\r\n        <file>qml/Login/LoginPanel/LoginPage.qml</file>\r\n        <file>qml/Login/main.qml</file>\r\n        <file>qml/Login/MyLoginButton.qml</file>\r\n        <file>qml/Login/SettingPage.qml</file>\r\n        <file>qml/MainPanel/ListPage/AllListPage.qml</file>\r\n        <file>qml/MainPanel/ListPage/DiscuList.qml</file>\r\n        <file>qml/MainPanel/ListPage/FriendList.qml</file>\r\n        <file>qml/MainPanel/ListPage/GroupAndDiscuPage.qml</file>\r\n        <file>qml/MainPanel/ListPage/GroupList.qml</file>\r\n        <file>qml/MainPanel/ListPage/RecentList.qml</file>\r\n        <file>qml/MainPanel/main.qml</file>\r\n        <file>qml/MainPanel/MainPanelPage.qml</file>\r\n        <file>qml/Utility/ComboBox/MyComboBox.qml</file>\r\n        <file>qml/Utility/ComboBox/MyComboBoxComponent.qml</file>\r\n        <file>qml/Utility/KeyboardPage/SoftKeyboard.qml</file>\r\n        <file>qml/Utility/KeyboardPage/SoftKeyboardButton.qml</file>\r\n        <file>qml/Utility/CodeInput.qml</file>\r\n        <file>qml/Utility/MyButton.qml</file>\r\n        <file>qml/Utility/MyMessageBox.qml</file>\r\n        <file>qml/Utility/MyRectangularGlow.qml</file>\r\n        <file>qml/Utility/MyScrollView.qml</file>\r\n        <file>qml/Utility/MyTextArea.qml</file>\r\n        <file>qml/Utility/MyTextField.qml</file>\r\n        <file>qml/Utility/MyTextView.qml</file>\r\n        <file>qml/Utility/MyWindow.qml</file>\r\n        <file>qml/Utility/SystemTray.qml</file>\r\n        <file>qml/Utility/TrayMessageWindow.qml</file>\r\n    </qresource>\r\n</RCC>\r\n"
  },
  {
    "path": "qmlapplicationviewer.pri",
    "content": "# checksum 0x5b42 version 0x70013\n# This file was generated by the Qt Quick Application wizard of Qt Creator.\n# The code below adds the QmlApplicationViewer to the project and handles the\n# activation of QML debugging.\n# It is recommended not to modify this file, since newer versions of Qt Creator\n# may offer an updated version of it.\n\n#QT += declarative\n\nS#OURCES += $$PWD/qmlapplicationviewer.cpp\n#HEADERS += $$PWD/qmlapplicationviewer.h\nINCLUDEPATH += $$PWD\n\n# Include JS debugger library if QMLJSDEBUGGER_PATH is set\n!isEmpty(QMLJSDEBUGGER_PATH) {\n    include($$QMLJSDEBUGGER_PATH/qmljsdebugger-lib.pri)\n} else {\n    DEFINES -= QMLJSDEBUGGER\n}\n\ncontains(CONFIG,qdeclarative-boostable):contains(MEEGO_EDITION,harmattan) {\n    DEFINES += HARMATTAN_BOOSTER\n}\n# This file was generated by an application wizard of Qt Creator.\n# The code below handles deployment to Symbian and Maemo, aswell as copying\n# of the application data to shadow build directories on desktop.\n# It is recommended not to modify this file, since newer versions of Qt Creator\n# may offer an updated version of it.\n\ndefineTest(qtcAddDeployment) {\nfor(deploymentfolder, DEPLOYMENTFOLDERS) {\n    item = item$${deploymentfolder}\n    itemsources = $${item}.sources\n    $$itemsources = $$eval($${deploymentfolder}.source)\n    itempath = $${item}.path\n    $$itempath= $$eval($${deploymentfolder}.target)\n    export($$itemsources)\n    export($$itempath)\n    DEPLOYMENT += $$item\n}\n\nMAINPROFILEPWD = $$PWD\n\nsymbian {\n    isEmpty(ICON):exists($${TARGET}.svg):ICON = $${TARGET}.svg\n    isEmpty(TARGET.EPOCHEAPSIZE):TARGET.EPOCHEAPSIZE = 0x20000 0x2000000\n} else:win32 {\n    copyCommand =\n    for(deploymentfolder, DEPLOYMENTFOLDERS) {\n        source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source)\n        source = $$replace(source, /, \\\\)\n        sourcePathSegments = $$split(source, \\\\)\n        target = $$OUT_PWD/$$eval($${deploymentfolder}.target)/$$last(sourcePathSegments)\n        target = $$replace(target, /, \\\\)\n        target ~= s,\\\\\\\\\\\\.?\\\\\\\\,\\\\,\n        !isEqual(source,$$target) {\n            !isEmpty(copyCommand):copyCommand += &&\n            isEqual(QMAKE_DIR_SEP, \\\\) {\n                copyCommand += $(COPY_DIR) \\\"$$source\\\" \\\"$$target\\\"\n            } else {\n                source = $$replace(source, \\\\\\\\, /)\n                target = $$OUT_PWD/$$eval($${deploymentfolder}.target)\n                target = $$replace(target, \\\\\\\\, /)\n                copyCommand += test -d \\\"$$target\\\" || mkdir -p \\\"$$target\\\" && cp -r \\\"$$source\\\" \\\"$$target\\\"\n            }\n        }\n    }\n    !isEmpty(copyCommand) {\n        copyCommand = @echo Copying application data... && $$copyCommand\n        copydeploymentfolders.commands = $$copyCommand\n        first.depends = $(first) copydeploymentfolders\n        export(first.depends)\n        export(copydeploymentfolders.commands)\n        QMAKE_EXTRA_TARGETS += first copydeploymentfolders\n    }\n} else:unix {\n    maemo5 {\n        desktopfile.files = $${TARGET}.desktop\n        desktopfile.path = /usr/share/applications/hildon\n        icon.files = $${TARGET}64.png\n        icon.path = /usr/share/icons/hicolor/64x64/apps\n    } else:!isEmpty(MEEGO_VERSION_MAJOR) {\n        desktopfile.files = $${TARGET}_harmattan.desktop\n        desktopfile.path = /usr/share/applications\n        icon.files = $${TARGET}80.png\n        icon.path = /usr/share/icons/hicolor/80x80/apps\n    } else { # Assumed to be a Desktop Unix\n        copyCommand =\n        for(deploymentfolder, DEPLOYMENTFOLDERS) {\n            source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source)\n            source = $$replace(source, \\\\\\\\, /)\n            macx {\n                target = $$OUT_PWD/$${TARGET}.app/Contents/Resources/$$eval($${deploymentfolder}.target)\n            } else {\n                target = $$OUT_PWD/$$eval($${deploymentfolder}.target)\n            }\n            target = $$replace(target, \\\\\\\\, /)\n            sourcePathSegments = $$split(source, /)\n            targetFullPath = $$target/$$last(sourcePathSegments)\n            targetFullPath ~= s,/\\\\.?/,/,\n            !isEqual(source,$$targetFullPath) {\n                !isEmpty(copyCommand):copyCommand += &&\n                copyCommand += $(MKDIR) \\\"$$target\\\"\n                copyCommand += && $(COPY_DIR) \\\"$$source\\\" \\\"$$target\\\"\n            }\n        }\n        !isEmpty(copyCommand) {\n            copyCommand = @echo Copying application data... && $$copyCommand\n            copydeploymentfolders.commands = $$copyCommand\n            first.depends = $(first) copydeploymentfolders\n            export(first.depends)\n            export(copydeploymentfolders.commands)\n            QMAKE_EXTRA_TARGETS += first copydeploymentfolders\n        }\n    }\n    installPrefix = /opt/$${TARGET}\n    for(deploymentfolder, DEPLOYMENTFOLDERS) {\n        item = item$${deploymentfolder}\n        itemfiles = $${item}.files\n        $$itemfiles = $$eval($${deploymentfolder}.source)\n        itempath = $${item}.path\n        $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target)\n        export($$itemfiles)\n        export($$itempath)\n        INSTALLS += $$item\n    }\n\n    !isEmpty(desktopfile.path) {\n        export(icon.files)\n        export(icon.path)\n        export(desktopfile.files)\n        export(desktopfile.path)\n        INSTALLS += icon desktopfile\n    }\n\n    target.path = $${installPrefix}/bin\n    export(target.path)\n    INSTALLS += target\n}\n\nexport (ICON)\nexport (INSTALLS)\nexport (DEPLOYMENT)\nexport (TARGET.EPOCHEAPSIZE)\nexport (TARGET.CAPABILITY)\nexport (LIBS)\nexport (QMAKE_EXTRA_TARGETS)\n}\n"
  },
  {
    "path": "src/main.cpp",
    "content": "#include <QApplication>\r\n#include <QDebug>\r\n#include <QWidget>\r\n#include <QNetworkProxy>\r\n#include <QNetworkRequest>\r\n#include <QQmlContext>\r\n#include <QQmlApplicationEngine>\r\n#include <QScreen>\r\n#include <QFileDialog>\r\n#include \"mynetworkaccessmanagerfactory.h\"\r\n#include \"systemtrayicon.h\"\r\n#include \"utility.h\"\r\n#include \"mywindow.h\"\r\n#include \"qqstars.h\"\r\n#include \"myimage.h\"\r\n#include \"mysvgview.h\"\r\n#include \"myshortcut.h\"\r\n#include \"myhttprequest.h\"\r\n#include \"mymessagebox.h\"\r\n#include \"downloadimage.h\"\r\n#include \"texteditplaygif.h\"\r\n#include <QWebView>\r\n\r\nint main(int argc, char *argv[])\r\n{\r\n    QApplication app(argc, argv);\r\n    \r\n    app.setApplicationName (\"QQStars\");\r\n    app.setApplicationVersion (\"1.0.0\");\r\n    app.setOrganizationName (\"雨后星辰\");\r\n    app.setApplicationDisplayName (\"星辰QQ\");\r\n    \r\n    QTranslator *translator = new QTranslator;\r\n    translator->load (\":/qt_zh_CN.qm\");\r\n    QApplication::installTranslator (translator);\r\n    \r\n    QQmlApplicationEngine *engine = new QQmlApplicationEngine;\r\n    engine->setNetworkAccessManagerFactory (new MyNetworkAccessManagerFactory());//给qml设置网络请求所用的类\r\n    \r\n    qmlRegisterType<TextEditPlayGif>(\"MyTextEditPlugin\", 1, 0, \"TextEditPlayGif\");\r\n    qmlRegisterType<MyWindow>(\"mywindow\", 1,0, \"MyQuickWindow\");\r\n    qmlRegisterType<SystemTrayIcon>(\"mywindow\", 1,0, \"MySystemTrayIcon\");\r\n    qmlRegisterType<MyMenu>(\"mywindow\", 1,0, \"MyMenu\");\r\n    qmlRegisterType<MenuSeparator>(\"mywindow\", 1,0, \"MenuSeparator\");\r\n    qmlRegisterType<MyMenuItem>(\"mywindow\", 1,0, \"MyMenuItem\");\r\n    qmlRegisterType<MyShortcut>(\"utility\", 1,0, \"MyShortcut\");\r\n    qmlRegisterType<DownloadImage>(\"utility\", 1, 0, \"DownloadImage\");\r\n    qmlRegisterType<QQCommand>(\"qqstars\", 1,0, \"QQ\");\r\n    qmlRegisterType<FriendInfo>(\"QQItemInfo\", 1,0, \"FriendInfo\");\r\n    qmlRegisterType<GroupInfo>(\"QQItemInfo\", 1,0, \"GroupInfo\");\r\n    qmlRegisterType<DiscuInfo>(\"QQItemInfo\", 1,0, \"DiscuInfo\");\r\n    qmlRegisterType<QQItemInfo>(\"QQItemInfo\", 1,0, \"QQItemInfo\");\r\n    qmlRegisterType<ChatMessageInfo>(\"QQItemInfo\", 1, 0, \"ChatMessageInfo\");\r\n    qmlRegisterType<ChatMessageInfoList>(\"QQItemInfo\", 1, 0, \"ChatMessageInfoList\");\r\n    qmlRegisterType<MyImage>(\"mywindow\", 1,0, \"MyImage\");\r\n    qmlRegisterType<MySvgView>(\"mywindow\", 1, 0, \"SvgView\");\r\n    qmlRegisterType<MyMessageBox>(\"mywindow\", 1, 0, \"MessageBox\");\r\n   \r\n    Utility *utility=Utility::createUtilityClass ();\r\n    QNetworkRequest* request = utility->getHttpRequest ()->getNetworkRequest ();\r\n    request->setRawHeader (\"Referer\", \"http://d.web2.qq.com/proxy.html?v=20110331002&callback=1&id=2\");//和腾讯服务器打交道需要设置这个\r\n    request->setHeader (QNetworkRequest::ContentTypeHeader, \"application/x-www-form-urlencoded\");\r\n    \r\n    request = utility->getDownloadImage ()->getHttpRequest ()->getNetworkRequest ();\r\n    request->setRawHeader (\"Referer\", \"http://web2.qq.com/webqq.html\");//需要设置这个，不然腾讯服务器不响应你的请求\r\n    request->setRawHeader (\"Accept\", \"image/webp,*/*;q=0.8\");\r\n    \r\n    utility->initUtility (new QSettings, engine);\r\n    \r\n    QQmlComponent component0(engine, QUrl(\"qrc:/qml/Api/QQApi.qml\"));\r\n    QQCommand *qqapi = qobject_cast<QQCommand *>(component0.create ());\r\n\r\n    engine->rootContext ()->setContextProperty (\"myqq\", qqapi);\r\n    \r\n    QQmlComponent component(engine, QUrl(\"qrc:/qml/Utility/SystemTray.qml\"));\r\n    SystemTrayIcon *systemTray = qobject_cast<SystemTrayIcon *>(component.create ());\r\n#ifdef Q_OS_WIN\r\n    systemTray->setParent (Utility::createUtilityClass ());//不设置父对象会导致程序退出后托盘还存在的问题\r\n#endif\r\n    engine->rootContext ()->setContextProperty (\"systemTray\", systemTray);//将程序托盘注册过去\r\n    qqapi->loadLoginWindow ();//加载登录窗口\r\n    \r\n    return app.exec();\r\n}\r\n"
  },
  {
    "path": "src/mywidgets/myimage.cpp",
    "content": "#include \"myimage.h\"\r\n#include <QPainter>\r\n#include <QBitmap>\r\n#include <QDir>\r\n#include <QDebug>\r\n#include <QPixmapCache>\r\n\r\nQCache<QString, QPixmap> MyImage::pixmapCache;\r\n\r\n#if(QT_VERSION>=0x050000)\r\nMyImage::MyImage(QQuickItem *parent) :\r\n    QQuickPaintedItem(parent)\r\n#else\r\nMyImage::MyImage(QDeclarativeItem *parent) :\r\n    QDeclarativeItem(parent)\r\n#endif\r\n{\r\n#if(QT_VERSION<0x050000)\r\n    setFlag(QGraphicsItem::ItemHasNoContents, false);\r\n#endif\r\n    m_status = Null;\r\n    m_cache = true;\r\n    m_grayscale = false;\r\n    m_source = \"\";\r\n    m_sourceSize = QSize(0,0);\r\n    m_defaultSize = QSize(0,0);\r\n    pixmap = NULL;\r\n    reply = NULL;\r\n\r\n    connect(&manager, SIGNAL(finished(QNetworkReply*)), SLOT(onDownImageFinished(QNetworkReply*)));\r\n}\r\n\r\nMyImage::~MyImage()\r\n{\r\n    if(pixmap!=NULL)\r\n        delete pixmap;\r\n}\r\n\r\nQUrl MyImage::source() const\r\n{\r\n    return m_source;\r\n}\r\n\r\nQUrl MyImage::maskSource() const\r\n{\r\n    return m_maskSource;\r\n}\r\n\r\nbool MyImage::cache() const\r\n{\r\n    return m_cache;\r\n}\r\n\r\nbool MyImage::grayscale() const\r\n{\r\n    return m_grayscale;\r\n}\r\n\r\nvoid MyImage::chromaticToGrayscale(QImage &image)\r\n{\r\n    if(image.isNull()||image.isGrayscale ())\r\n        return;\r\n    for(int i=0;i<image.width ();++i){\r\n        for(int j=0;j<image.height ();++j){\r\n            QRgb pixel = image.pixel(i,j);\r\n            int a = qAlpha(pixel);\r\n            pixel = qGray (pixel);\r\n            pixel = qRgba(pixel,pixel,pixel,a);\r\n            image.setPixel (i,j,pixel);\r\n        }\r\n    }\r\n}\r\n\r\nQString MyImage::imageFormatToString(const QByteArray &array)\r\n{\r\n    QByteArray str = array.toHex ();\r\n    if(str.mid (2,6)==\"504e47\")\r\n        return \"png\";\r\n    if(str.mid (12,8)==\"4a464946\")\r\n        return \"jpg\";\r\n    if(str.left (6)==\"474946\")\r\n        return \"gif\";\r\n    if(str.left (4)==\"424d\")\r\n        return \"bmp\";\r\n    return \"\";\r\n}\r\n\r\nvoid MyImage::downloadImage(const QUrl &url)\r\n{\r\n    setStatus(Loading);\r\n\r\n    if(reply!=NULL){\r\n        reply->abort();\r\n        //先结束上次的网络请求\r\n    }\r\n\r\n    QNetworkRequest request;\r\n    request.setUrl(url);\r\n    reply = manager.get(request);\r\n}\r\n\r\nvoid MyImage::setImage(QImage &image)\r\n{\r\n    setDefaultSize(image.size());\r\n\r\n    if(m_cache){\r\n        QPixmap *temp_pixmap = new QPixmap(QPixmap::fromImage(image));\r\n        pixmapCache.insert(m_source.toString(), temp_pixmap);\r\n    }\r\n\r\n    QSize temp_size = m_sourceSize;\r\n    if(temp_size==QSize(0,0)){\r\n        temp_size = m_defaultSize;\r\n    }else if(temp_size.width()==0){\r\n        temp_size.setWidth((double)temp_size.height()/m_defaultSize.height()*m_defaultSize.width());\r\n    }else if(temp_size.height()==0){\r\n        temp_size.setHeight((double)temp_size.width()/m_defaultSize.width()*m_defaultSize.height());\r\n    }\r\n    if(m_defaultSize!=temp_size)\r\n        image = image.scaled(temp_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);\r\n\r\n    if(m_grayscale){//如果为黑白\r\n        chromaticToGrayscale(image);//转换为黑白图\r\n    }\r\n\r\n    if(pixmap!=NULL)\r\n        delete pixmap;\r\n    pixmap = new QPixmap(QPixmap::fromImage(image));\r\n\r\n    QString str = m_maskSource.toLocalFile();\r\n    if(str==\"\"){\r\n        str = m_maskSource.toString();\r\n    }\r\n    if(str!=\"\"){\r\n        if( str.mid (0, 3) == \"qrc\")\r\n            str = str.mid (3, str.count ()-3);\r\n        QBitmap bitmap(str);\r\n        if(!bitmap.isNull()){\r\n            int max_width = bitmap.width();\r\n            int max_height = bitmap.height();\r\n            max_width = pixmap->width()>max_width?pixmap->width():max_width;\r\n            max_height = pixmap->height()>max_height?pixmap->height():max_height;\r\n\r\n            QPixmap temp_pixmap = pixmap->scaled(max_width, max_height);\r\n            temp_pixmap.setMask (bitmap.scaled(temp_pixmap.size()));\r\n            *pixmap = temp_pixmap.scaled(image.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);\r\n        }\r\n    }\r\n\r\n    setImplicitWidth(image.width());\r\n    setImplicitHeight(image.height());\r\n\r\n    update();\r\n\r\n    setStatus(Ready);\r\n    emit loadReady();\r\n}\r\n\r\nvoid MyImage::onDownImageFinished(QNetworkReply *reply)\r\n{\r\n    if(reply->error() == QNetworkReply::NoError){\r\n        QImage image;\r\n        if( !image.loadFromData(reply->readAll())){\r\n            emit loadError ();\r\n            setStatus(Error);\r\n            return;\r\n        }\r\n        setImage(image);\r\n    }else{\r\n        setStatus(Error);\r\n        emit loadError();\r\n    }\r\n}\r\n\r\n#if(QT_VERSION>=0x050000)\r\nvoid MyImage::paint(QPainter *painter)\r\n#else\r\nvoid MyImage::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)\r\n#endif\r\n{\r\n    if(pixmap==NULL||pixmap->isNull())\r\n        return;\r\n\r\n    if(smooth())\r\n        painter->setRenderHint(QPainter::SmoothPixmapTransform);\r\n    painter->drawPixmap (boundingRect().toRect(), *pixmap);\r\n}\r\n\r\nMyImage::State MyImage::status() const\r\n{\r\n    return m_status;\r\n}\r\n\r\nQSize MyImage::sourceSize() const\r\n{\r\n    return m_sourceSize;\r\n}\r\n\r\nQSize MyImage::defaultSize() const\r\n{\r\n    return m_defaultSize;\r\n}\r\n\r\nconst QPixmap *MyImage::getPixmap() const\r\n{\r\n    return pixmap;\r\n}\r\n\r\nvoid MyImage::setSource(QUrl arg)\r\n{\r\n    if (!m_cache||m_source != arg) {\r\n        setStatus(Loading);\r\n        bool can_emit = m_source==arg;\r\n        m_source = arg;\r\n        reLoad();\r\n        //加载图片\r\n        if(can_emit)\r\n            emit sourceChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyImage::setMaskSource(QUrl arg)\r\n{\r\n    if (m_maskSource != arg) {\r\n        m_maskSource = arg;\r\n        if(pixmap!=NULL)\r\n            reLoad();\r\n        emit maskSourceChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyImage::setCache(bool arg)\r\n{\r\n    if (m_cache != arg) {\r\n        m_cache = arg;\r\n        if(!m_cache){\r\n            QPixmap* temp_pixmap = pixmapCache.object(m_source.toString());\r\n            pixmapCache.remove(m_source.toString());\r\n            if(temp_pixmap!=NULL)\r\n                delete temp_pixmap;\r\n        }\r\n        emit cacheChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyImage::setGrayscale(bool arg)\r\n{\r\n    if(m_grayscale!=arg){\r\n        m_grayscale = arg;\r\n        if(pixmap!=NULL){\r\n            if(m_grayscale){\r\n                QImage image = pixmap->toImage();\r\n                chromaticToGrayscale(image);\r\n                *pixmap = QPixmap::fromImage(image);\r\n                update();\r\n            }else{\r\n                reLoad();\r\n            }\r\n        }\r\n        emit grayscaleChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyImage::setStatus(MyImage::State arg)\r\n{\r\n    if (m_status != arg) {\r\n        m_status = arg;\r\n        emit statusChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyImage::reLoad()\r\n{\r\n    QString str = m_source.toLocalFile();\r\n    if(str == \"\"){\r\n        str = m_source.toString();\r\n        if(str==\"\"){\r\n            if(pixmap!=NULL){\r\n                delete pixmap;\r\n                pixmap = NULL;\r\n            }\r\n            return;\r\n        }\r\n    }\r\n\r\n    QPixmap *temp_pixmap = pixmapCache.object(m_source.toString());\r\n    if(temp_pixmap!=NULL){\r\n        bool temp_cache = m_cache;\r\n        m_cache = false;//先设置false，防止setImage中再次更新缓存\r\n        QImage image = temp_pixmap->toImage();\r\n        setImage(image);\r\n        m_cache = temp_cache;\r\n        return;\r\n    }\r\n\r\n    if(str.indexOf(\"http\")==0){//如果是网络图片\r\n        downloadImage(m_source);\r\n        return;\r\n    }\r\n\r\n    if( str.mid (0, 3) == \"qrc\")\r\n        str = str.mid (3, str.count ()-3);\r\n\r\n    QImage image;\r\n    if( !image.load (str)){\r\n        emit loadError ();\r\n        setStatus(Error);\r\n        return;\r\n    }\r\n\r\n    setImage(image);\r\n}\r\n\r\nvoid MyImage::setSourceSize(QSize arg)\r\n{\r\n    if (m_sourceSize != arg) {\r\n        m_sourceSize = arg;\r\n        if(pixmap!=NULL)\r\n            reLoad();\r\n        emit sourceSizeChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyImage::setDefaultSize(QSize arg)\r\n{\r\n    if (m_defaultSize != arg) {\r\n        m_defaultSize = arg;\r\n        emit defaultSizeChanged(arg);\r\n    }\r\n}\r\n\r\nbool MyImage::save(const QString& fileName) const\r\n{\r\n    if(pixmap!=NULL){\r\n        return pixmap->save(fileName);\r\n    }\r\n    return false;\r\n}\r\n"
  },
  {
    "path": "src/mywidgets/myimage.h",
    "content": "#ifndef MYIMAGE_H\r\n#define MYIMAGE_H\r\n\r\n#include <QImage>\r\n#include <QPixmap>\r\n#include <QBitmap>\r\n#include <QtNetwork>\r\n#include <QCache>\r\n#if(QT_VERSION>=0x050000)\r\n#include <QQuickPaintedItem>\r\n#else\r\n#include <QDeclarativeItem>\r\n#endif\r\n\r\n#if(QT_VERSION>=0x050000)\r\nclass MyImage : public QQuickPaintedItem\r\n#else\r\nclass MyImage : public QDeclarativeItem\r\n#endif\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QUrl maskSource READ maskSource WRITE setMaskSource NOTIFY maskSourceChanged)\r\n    Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged)\r\n    Q_PROPERTY(bool grayscale READ grayscale WRITE setGrayscale NOTIFY grayscaleChanged)\r\n    Q_PROPERTY(State status READ status NOTIFY statusChanged FINAL)\r\n    Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize NOTIFY sourceSizeChanged)\r\n    Q_PROPERTY(QSize defaultSize READ defaultSize NOTIFY defaultSizeChanged FINAL)\r\n    Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)\r\n\r\n    Q_ENUMS(State)\r\npublic:\r\n    enum State{\r\n        Null,\r\n        Ready,\r\n        Loading,\r\n        Error\r\n    };\r\n\r\n#if(QT_VERSION>=0x050000)\r\n    explicit MyImage(QQuickItem *parent = 0);\r\n#else\r\n    explicit MyImage(QDeclarativeItem *parent = 0);\r\n#endif\r\n    ~MyImage();\r\n\r\n    QUrl source() const;\r\n    QUrl maskSource() const;\r\n    bool cache() const;\r\n    bool grayscale() const;\r\n    \r\n    void chromaticToGrayscale(QImage &image);\r\n    static QString imageFormatToString(const QByteArray& array);\r\n\r\n#if(QT_VERSION>=0x050000)\r\n    void paint(QPainter * painter);\r\n#else\r\n    void paint(QPainter *painter, const QStyleOptionGraphicsItem *new_style, QWidget *new_widget=0);\r\n#endif\r\n    State status() const;\r\n    QSize sourceSize() const;\r\n    QSize defaultSize() const;\r\n\r\n    const QPixmap* getPixmap() const;\r\nsignals:\r\n    void sourceChanged(QUrl arg);\r\n    void maskSourceChanged(QUrl arg);\r\n    void loadError();//加载图片出错\r\n    void loadReady();\r\n    void cacheChanged(bool arg);\r\n    void grayscaleChanged(bool arg);\r\n    void statusChanged(State arg);\r\n    void sourceSizeChanged(QSize arg);\r\n    void defaultSizeChanged(QSize arg);\r\n\r\npublic slots:\r\n    void setSource(QUrl arg);\r\n    void setMaskSource(QUrl arg);\r\n    void setCache(bool arg);\r\n    void setGrayscale(bool arg);\r\n    void setStatus(State arg);\r\n    void reLoad();\r\n    void setSourceSize(QSize arg);\r\n    void setDefaultSize(QSize arg);\r\n    bool save(const QString& fileName) const;\r\n\r\nprivate slots:\r\n    void onDownImageFinished(QNetworkReply* reply);\r\n\r\nprivate:\r\n    QUrl m_source;\r\n    QPixmap *pixmap;\r\n    static QCache<QString, QPixmap> pixmapCache;\r\n\r\n    QUrl m_maskSource;\r\n    bool m_cache;\r\n    bool m_grayscale;\r\n    QNetworkAccessManager manager;\r\n    QNetworkReply *reply;\r\n    State m_status;\r\n    QSize m_sourceSize;\r\n    QSize m_defaultSize;\r\n\r\n    void downloadImage(const QUrl& url);\r\n    void setImage(QImage& image);\r\n};\r\n\r\n#endif // MYIMAGE_H\r\n"
  },
  {
    "path": "src/mywidgets/mymessagebox.cpp",
    "content": "#include \"mymessagebox.h\"\r\n#include <QMouseEvent>\r\n#include <QDebug>\r\n#include <QLabel>\r\n#include <QPainter>\r\n#include <QPaintEngine>\r\n\r\nMyMessageBox::MyMessageBox(QWidget *parent) :\r\n    QMessageBox(parent)\r\n{\r\n    //setAttribute(Qt::WA_TranslucentBackground);\r\n    setFixedSize (300, 200);\r\n    setWindowFlags (windowFlags ()|Qt::FramelessWindowHint);\r\n    //QImage image(\":/images/menu_background.png\");\r\n    //background_pixmap = QPixmap::fromImage (image);\r\n    //QLabel *label = new QLabel(this);\r\n    //label->setPixmap (background_pixmap);\r\n    //label->setGeometry (0,0,width(),height ());\r\n    //label->setBackgroundRole ();\r\n}\r\n\r\nQUrl MyMessageBox::styleSource() const\r\n{\r\n    return m_styleSource;\r\n}\r\n\r\nvoid MyMessageBox::mousePressEvent(QMouseEvent *event)\r\n{\r\n    if(event->button () == Qt::LeftButton){\r\n        press_point = event->pos ();\r\n        allow_move = true;\r\n        event->accept ();\r\n    }else{\r\n        QMessageBox::mousePressEvent (event);\r\n    }\r\n}\r\n\r\nvoid MyMessageBox::mouseMoveEvent(QMouseEvent *event)\r\n{\r\n    if(allow_move){\r\n        move (pos()+event->pos ()-press_point);\r\n        event->accept ();\r\n    }else{\r\n        QMessageBox::mouseMoveEvent (event);\r\n    }\r\n}\r\n\r\nvoid MyMessageBox::mouseReleaseEvent(QMouseEvent *event)\r\n{\r\n    if(event->button () == Qt::LeftButton){\r\n        allow_move = false;\r\n        event->accept ();\r\n    }else{\r\n        QMessageBox::mouseReleaseEvent (event);\r\n    }\r\n}\r\n\r\nvoid MyMessageBox::setStyleSource(QUrl arg)\r\n{\r\n    if (m_styleSource != arg) {\r\n        m_styleSource = arg;\r\n        QFile file(arg.toLocalFile ());\r\n        if(file.open (QIODevice::ReadOnly)){\r\n            setStyleSheet (file.readAll ());\r\n        }else{\r\n            qDebug()<<\"打开\"+arg.toLocalFile ()+\"失败；\"<<file.errorString ();\r\n        }\r\n        file.close ();\r\n        emit styleSourceChanged(arg);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/mywidgets/mymessagebox.h",
    "content": "#ifndef MYMESSAGEBOX_H\r\n#define MYMESSAGEBOX_H\r\n\r\n#include <QMessageBox>\r\n#include <QUrl>\r\n#include <QPixmap>\r\n\r\nclass MyMessageBox : public QMessageBox\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QUrl styleSource READ styleSource WRITE setStyleSource NOTIFY styleSourceChanged)\r\n    \r\npublic:\r\n    explicit MyMessageBox(QWidget *parent = 0);\r\n    QUrl styleSource() const;\r\n    \r\nprivate:\r\n     void mousePressEvent(QMouseEvent * event);\r\n     void mouseMoveEvent(QMouseEvent * event);\r\n     void mouseReleaseEvent(QMouseEvent * event);\r\n\r\n     QUrl m_styleSource;\r\n     QPoint press_point;\r\n     bool allow_move;\r\n     \r\n     QPixmap *background_pixmap;\r\nsignals:\r\n    void styleSourceChanged(QUrl arg);\r\npublic slots:\r\n    void setStyleSource(QUrl arg);\r\n};\r\n\r\n#endif // MYMESSAGEBOX_H\r\n"
  },
  {
    "path": "src/mywidgets/mysvgview.cpp",
    "content": "﻿#include \"mysvgview.h\"\r\n#include <QPainter>\r\n#include <QSvgRenderer>\r\n#include <QDebug>\r\n\r\n#if(QT_VERSION>=0x050000)\r\nMySvgView::MySvgView(QQuickItem *parent) :\r\n    QQuickPaintedItem(parent)\r\n#else\r\nMySvgView::MySvgView(QDeclarativeItem *parent) :\r\n    QDeclarativeItem(parent)\r\n#endif\r\n{\r\n#if(QT_VERSION<0x050000)\r\n    setFlag(QGraphicsItem::ItemHasNoContents, false);\r\n#endif\r\n    m_defaultSize = QSize(0,0);\r\n    svg = new QSvgRenderer(this);\r\n}\r\n\r\nQUrl MySvgView::source() const\r\n{\r\n    return m_source;\r\n}\r\n\r\nQSize MySvgView::defaultSize() const\r\n{\r\n    return m_defaultSize;\r\n}\r\n\r\nvoid MySvgView::setDefaultSize(QSize arg)\r\n{\r\n    if(arg!=m_defaultSize){\r\n        m_defaultSize = arg;\r\n        emit defaultSizeChanged (arg);\r\n    }\r\n}\r\n\r\n#if(QT_VERSION>=0x050000)\r\nvoid MySvgView::paint(QPainter *painter)\r\n#else\r\nvoid MySvgView::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)\r\n#endif\r\n{\r\n    svg->render (painter, boundingRect());\r\n}\r\n\r\nvoid MySvgView::setSource(QUrl arg)\r\n{\r\n    if (m_source != arg) {\r\n        m_source = arg;\r\n\r\n        QString str = m_source.toLocalFile();\r\n        if(str == \"\"){\r\n            str = m_source.toString();\r\n            if(str==\"\"){\r\n                svg->deleteLater();\r\n                svg = new QSvgRenderer(this);\r\n                return;\r\n            }\r\n        }\r\n            \r\n        if( str.mid (0, 3) == \"qrc\")\r\n            str = str.mid (3, str.count ()-3);\r\n        svg->load (str);\r\n        setDefaultSize (svg->defaultSize ());\r\n        int width = svg->defaultSize ().width ();\r\n        int height = svg->defaultSize ().height ();\r\n        setImplicitWidth(width);\r\n        setImplicitHeight(height);\r\n        update ();\r\n        emit sourceChanged(arg);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/mywidgets/mysvgview.h",
    "content": "#ifndef MYSVGVIEW_H\r\n#define MYSVGVIEW_H\r\n\r\n#include <QSvgRenderer>\r\n#if(QT_VERSION>=0x050000)\r\n#include <QQuickPaintedItem>\r\n#else\r\n#include <QDeclarativeItem>\r\n#endif\r\n\r\n#if(QT_VERSION>=0x050000)\r\nclass MySvgView : public QQuickPaintedItem\r\n#else\r\nclass MySvgView : public QDeclarativeItem\r\n#endif\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)\r\n    Q_PROPERTY(QSize defaultSize READ defaultSize WRITE setDefaultSize NOTIFY defaultSizeChanged FINAL)\r\n\r\npublic:\r\n#if(QT_VERSION>=0x050000)\r\n    explicit MySvgView(QQuickItem *parent = 0);\r\n#else\r\n    explicit MySvgView(QDeclarativeItem *parent = 0);\r\n#endif\r\n    QUrl source() const;\r\n    QSize defaultSize() const;\r\npublic slots:\r\n    void setSource(QUrl arg);\r\n    void setDefaultSize( QSize arg );\r\n\r\nsignals:\r\n    void sourceChanged(QUrl arg);\r\n    void rotationModeChanged(Qt::Axis arg);\r\n    void rotationOriginChanged(QPoint arg);\r\n    void defaultSizeChanged( QSize arg );\r\n\r\nprivate:\r\n    QSvgRenderer *svg;\r\n    QUrl m_source;\r\n    QSize m_defaultSize;\r\n\r\n#if(QT_VERSION>=0x050000)\r\n    void paint(QPainter * painter);\r\n#else\r\n    void paint(QPainter *painter, const QStyleOptionGraphicsItem *new_style, QWidget *new_widget=0);\r\n#endif\r\n};\r\n\r\n#endif // MYSVGVIEW_H\r\n"
  },
  {
    "path": "src/mywidgets/mywindow.cpp",
    "content": "#include \"mywindow.h\"\r\n#include \"utility.h\"\r\n#include <QDebug>\r\n#include <QQmlComponent>\r\n#include <QApplication>\r\n#include <QPainter>\r\n#include <QPainterPath>\r\n#include <QScreen>\r\n#ifdef Q_OS_WIN\r\n#include <winuser.h>\r\n#elif defined(Q_OS_LINUX)\r\n#include <X11/extensions/shape.h>\r\n#include <QX11Info>\r\n#endif\r\n#include <QWidget>\r\n\r\nbool test(QObject *, Qt::ShortcutContext)\r\n{\r\n    return true;\r\n}\r\n\r\nMyWindow::MyWindow(QQuickWindow *parent) :\r\n    QQuickWindow(parent)\r\n{\r\n    setObjectName (\"MyWindow\");\r\n    \r\n    m_noBorder = false;\r\n    m_windowStatus = StopCenter;\r\n    m_topHint = false;\r\n    old_topHint=false;\r\n    m_noNotifyIcon = false;\r\n    m_windowActive = false;\r\n    m_mousePenetrate = false;\r\n    m_minimumWidth = 0;\r\n    m_minimumHeight = 0;\r\n    m_maximumWidth = 9999999;\r\n    m_maximumHeight = 9999999;\r\n    \r\n    connect (this, &QQuickWindow::widthChanged, this, &MyWindow::actualWidthChanged);\r\n    connect (this, &QQuickWindow::heightChanged, this, &MyWindow::actualHeightChanged);\r\n    connect (this, &QQuickWindow::xChanged, this, &MyWindow::actualXChanged);\r\n    connect (this, &QQuickWindow::yChanged, this, &MyWindow::actualYChanged);\r\n    connect (this, &QQuickWindow::xChanged, this, &MyWindow::onActualXChanged);\r\n    connect (this, &QQuickWindow::yChanged, this, &MyWindow::onActualYChanged);\r\n    connect (contentItem (), &QQuickItem::xChanged, this, &MyWindow::xChanged);\r\n    connect (contentItem (), &QQuickItem::yChanged, this, &MyWindow::yChanged);\r\n}\r\n\r\nbool MyWindow::noNotifyIcon() const\r\n{\r\n    return m_noNotifyIcon;\r\n}\r\n\r\nint MyWindow::width() const\r\n{\r\n    return m_width;\r\n}\r\n\r\nint MyWindow::height() const\r\n{\r\n    return m_height;\r\n}\r\n\r\nint MyWindow::actualWidth() const\r\n{\r\n    return QQuickWindow::width ();\r\n}\r\n\r\nint MyWindow::actualHeight() const\r\n{\r\n    return QQuickWindow::height ();\r\n}\r\n\r\nbool MyWindow::windowActive() const\r\n{\r\n    return m_windowActive;\r\n}\r\n\r\nint MyWindow::x() const\r\n{\r\n    return QQuickWindow::x ()+contentItem ()->x ();\r\n}\r\n\r\nint MyWindow::y() const\r\n{\r\n    return QQuickWindow::y ()+contentItem ()->y ();\r\n}\r\n\r\nint MyWindow::actualX() const\r\n{\r\n    return QQuickWindow::x ();\r\n}\r\n\r\nint MyWindow::actualY() const\r\n{\r\n    return QQuickWindow::y ();\r\n}\r\n\r\nint MyWindow::minimumWidth() const\r\n{\r\n    return m_minimumWidth;\r\n}\r\n\r\nint MyWindow::minimumHeight() const\r\n{\r\n    return m_minimumHeight;\r\n}\r\n\r\nint MyWindow::maximumWidth() const\r\n{\r\n    return m_maximumWidth;\r\n}\r\n\r\nint MyWindow::maximumHeight() const\r\n{\r\n    return m_maximumHeight;\r\n}\r\n\r\nbool MyWindow::topHint() const\r\n{\r\n    return m_topHint;\r\n}\r\n\r\nbool MyWindow::mousePenetrate() const\r\n{\r\n    return m_mousePenetrate;\r\n}\r\n\r\nQPoint MyWindow::cursorPos() const\r\n{\r\n    return QCursor::pos();\r\n}\r\n\r\nQUrl MyWindow::windowIcon()\r\n{\r\n    return m_windowIcon;\r\n}\r\n\r\nvoid MyWindow::setWindowIcon(QUrl icon)\r\n{\r\n    if( icon!=m_windowIcon ){\r\n        QString str = icon.toString ();\r\n        if( str.mid (0, 3) == \"qrc\")\r\n            str = str.mid (3, str.count ()-3);\r\n        setIcon (QIcon(str));\r\n        m_windowIcon = icon;\r\n        emit windowIconChanged ();\r\n    }\r\n}\r\n\r\nvoid MyWindow::setWindowActive(bool arg)\r\n{\r\n    if(arg!=m_windowActive){\r\n        m_windowActive = arg;\r\n        emit windowActiveChanged (arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setMousePenetrateArea(QRect rect)\r\n{\r\n#ifdef Q_OS_LINUX\r\n    XRectangle* myrect = new XRectangle;\r\n    myrect->x = rect.x();\r\n    myrect->y = rect.y();\r\n    myrect->width = rect.width ();\r\n    myrect->height = rect.height ();\r\n    qDebug() << myrect->x << myrect->y << myrect->width << myrect->height;\r\n    XShapeCombineRectangles(QX11Info::display(), winId(), ShapeInput, 0,\r\n            0, myrect, 1, ShapeSet, YXBanded);\r\n#endif\r\n}\r\n\r\nvoid MyWindow::focusInEvent(QFocusEvent *ev)\r\n{\r\n    QQuickWindow::focusInEvent(ev);\r\n    setWindowActive (true);\r\n}\r\n\r\nvoid MyWindow::focusOutEvent(QFocusEvent *ev)\r\n{\r\n    QQuickWindow::focusOutEvent (ev);\r\n    setWindowActive (false);\r\n}\r\n\r\nvoid MyWindow::onActualXChanged()\r\n{\r\n    emit xChanged();\r\n}\r\n\r\nvoid MyWindow::onActualYChanged()\r\n{\r\n    emit yChanged();\r\n}\r\n\r\nbool MyWindow::noBorder()\r\n{\r\n    return m_noBorder;\r\n}\r\n\r\nvoid MyWindow::setNoBorder(bool isNoBroder)\r\n{\r\n    if( isNoBroder!=m_noBorder ) {\r\n        m_noBorder = isNoBroder;\r\n        if(!isVisible ()) {\r\n            if( isNoBroder )\r\n                setFlags (flags ()|Qt::FramelessWindowHint);\r\n            else\r\n                setFlags (flags ()&~Qt::FramelessWindowHint);\r\n        }else{\r\n            if( isNoBroder )\r\n                setFlags (flags ()|Qt::FramelessWindowHint);\r\n            else\r\n                setFlags (flags ()&~Qt::FramelessWindowHint);\r\n        }\r\n        \r\n        emit noBorderIconChanged();\r\n    }\r\n}\r\n\r\nMyWindow::WindowStatus MyWindow::windowStatus()\r\n{\r\n    return m_windowStatus;\r\n}\r\n\r\nvoid MyWindow::setWindowStatus(MyWindow::WindowStatus new_status)\r\n{\r\n    if( new_status!=m_windowStatus ) {\r\n        if( new_status == BerthPrepare&&m_windowStatus!=StopCenter ) {\r\n            setTopHint (old_topHint);\r\n        }else if(new_status!=StopCenter&&new_status!=BerthPrepare){\r\n            old_topHint = topHint ();\r\n            setTopHint (true);//设置窗口为最前端\r\n        }\r\n        m_windowStatus = new_status;\r\n        emit windowStatusChanged ();\r\n    }\r\n}\r\n\r\nint MyWindow::borderLeft()\r\n{\r\n#ifdef Q_OS_WIN\r\n    return 0;\r\n#elif defined(Q_OS_MACX)\r\n    return 0;\r\n#elif defined(Q_OS_LINUX)\r\n    return 65;\r\n#else\r\n    return 0;\r\n#endif\r\n}\r\n\r\nint MyWindow::borderRight()\r\n{\r\n#ifdef Q_OS_WIN\r\n    return QApplication::screens ()[0]->size ().width ();\r\n#elif defined(Q_OS_MACX)\r\n    return QApplication::screens ()[0]->size ().width ();\r\n#elif defined(Q_OS_LINUX)\r\n    return QApplication::screens ()[0]->size ().width ();\r\n#else\r\n    return QApplication::screens ()[0]->size ().width ();\r\n#endif\r\n}\r\n\r\nint MyWindow::borderTop()\r\n{\r\n#ifdef Q_OS_WIN\r\n    return 0;\r\n#elif defined(Q_OS_OSX)\r\n    return 0;\r\n#elif defined(Q_OS_LINUX)\r\n    return 25;\r\n#else\r\n    return 0;\r\n#endif\r\n}\r\n\r\n\r\nvoid MyWindow::setTopHint(bool arg)\r\n{\r\n    if (m_topHint != arg) {\r\n        m_topHint = arg;\r\n        if( arg ){\r\n            setFlags (flags ()|Qt::WindowStaysOnTopHint);\r\n#ifdef Q_OS_LINUX\r\n            if(isVisible()){\r\n                //setVisible(false);\r\n                //setVisible(true);\r\n                close();\r\n                show();\r\n            }\r\n#endif\r\n        }else{\r\n            setFlags (flags ()&~Qt::WindowStaysOnTopHint);\r\n#ifdef Q_OS_LINUX\r\n            if(isVisible()){\r\n                close();\r\n                show();\r\n                //setVisible(false);\r\n                //setVisible(true);\r\n            }\r\n#endif\r\n#ifdef Q_OS_WIN\r\n            SetWindowPos ((HWND)this->winId (),HWND_NOTOPMOST,0,0,width(),height(),SWP_NOSIZE|SWP_NOMOVE);\r\n#endif\r\n        }\r\n        emit topHintChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setNoNotifyIcon(bool arg)\r\n{\r\n    if ( m_noNotifyIcon != arg ) {\r\n        m_noNotifyIcon = arg;\r\n        if( arg )\r\n            setFlags (flags ()&~Qt::Tool);\r\n        else{\r\n            setFlags (flags ()|Qt::Tool);\r\n        }\r\n        emit noNotifyIconChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setWidth(int arg)\r\n{\r\n    if (m_width != arg&&arg<=maximumWidth ()&&arg>=minimumWidth ()) {\r\n        m_width = arg;\r\n        contentItem ()->setWidth (arg);\r\n        emit widthChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setHeight(int arg)\r\n{\r\n    if (m_height != arg&&arg<=maximumHeight ()&&arg>=minimumHeight ()) {\r\n        m_height = arg;\r\n        contentItem ()->setHeight (arg);\r\n        emit heightChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setActualWidth(int arg)\r\n{\r\n    QQuickWindow::setWidth (arg);\r\n}\r\n\r\nvoid MyWindow::setActualHeight(int arg)\r\n{\r\n    QQuickWindow::setHeight (arg);\r\n}\r\n\r\nvoid MyWindow::setX(int arg)\r\n{\r\n    QQuickWindow::setX (arg-contentItem ()->x ());\r\n}\r\n\r\nvoid MyWindow::setY(int arg)\r\n{\r\n    QQuickWindow::setY (arg-contentItem ()->y ());\r\n}\r\n\r\nvoid MyWindow::setActualX(int arg)\r\n{\r\n    QQuickWindow::setX (arg);\r\n}\r\n\r\nvoid MyWindow::setActualY(int arg)\r\n{\r\n    QQuickWindow::setY (arg);\r\n}\r\n\r\nvoid MyWindow::setMinimumWidth(int arg)\r\n{\r\n    if (m_minimumWidth != arg) {\r\n        m_minimumWidth = arg;\r\n        int temp = actualWidth ()-width();//算出真实宽和内容宽（不算阴影的宽）的差值\r\n        QQuickWindow::setMinimumWidth (temp+arg);//设置真实宽的限制\r\n        if(width()<arg){\r\n            setWidth (arg);\r\n        }\r\n        emit minimumWidthChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setMinimumHeight(int arg)\r\n{\r\n    if (m_minimumHeight != arg) {\r\n        m_minimumHeight = arg;\r\n        int temp = actualHeight ()-height();\r\n        QQuickWindow::setMinimumHeight (temp+arg);//设置真实高的限制\r\n        if(height()<arg){\r\n            setHeight (arg);\r\n        }\r\n        emit minimumHeightChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setMaximumWidth(int arg)\r\n{\r\n    if (m_maximumWidth != arg) {\r\n        m_maximumWidth = arg;\r\n        int temp = actualWidth ()-width();//算出真实宽和内容宽（不算阴影的宽）的差值\r\n        QQuickWindow::setMinimumWidth (temp+arg);//设置真实宽的限制\r\n        if(width()>arg){\r\n            setWidth (arg);\r\n        }\r\n        emit maximumWidthChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setMaximumHeight(int arg)\r\n{\r\n    if (m_maximumHeight != arg) {\r\n        m_maximumHeight = arg;\r\n        int temp = actualHeight ()-height();\r\n        QQuickWindow::setMinimumHeight (temp+arg);//设置真实高的限制\r\n        if(height()>arg){\r\n            setHeight (arg);\r\n        }\r\n        emit maximumHeightChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setMousePenetrate(bool arg)\r\n{\r\n    if (m_mousePenetrate != arg) {\r\n        m_mousePenetrate = arg;\r\n#ifdef Q_OS_LINUX\r\n        if(arg){\r\n            XShapeCombineRectangles(QX11Info::display(), winId(), ShapeInput, 0,\r\n                    0, NULL, 0, ShapeSet, YXBanded);\r\n        }else{\r\n            XRectangle* myrect = new XRectangle;\r\n            myrect->x = 0;\r\n            myrect->y = 0;\r\n            myrect->width = actualWidth ();\r\n            myrect->height = actualHeight ();\r\n            XShapeCombineRectangles(QX11Info::display(), winId(), ShapeInput, 0,\r\n                    0, myrect, 1, ShapeSet, YXBanded);\r\n        }\r\n#elif defined(Q_OS_OSX)\r\n        qDebug()<<\"mac os暂不支持鼠标穿透\";\r\n#elif defined(Q_OS_WIN)\r\n        HWND my_hwnd = (HWND)this->winId ();\r\n        if(arg){\r\n            SetWindowLong(my_hwnd, GWL_EXSTYLE,\r\n                         GetWindowLong(my_hwnd, GWL_EXSTYLE) | WS_EX_TRANSPARENT);\r\n        }else{\r\n            SetWindowLong(my_hwnd, GWL_EXSTYLE,\r\n                         GetWindowLong(my_hwnd, GWL_EXSTYLE)&(~WS_EX_TRANSPARENT));\r\n        }\r\n#endif\r\n        emit mousePenetrateChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyWindow::setCursorPos(QPoint cursorPos)\r\n{\r\n    QCursor::setPos(cursorPos);\r\n}\r\n\r\nvoid MyWindow::close()\r\n{\r\n    emit closeing ();\r\n    QQuickWindow::close ();\r\n}\r\n\r\nvoid MyWindow::deleteWindow()\r\n{\r\n    deleteLater ();//销毁自己\r\n}\r\n\r\n"
  },
  {
    "path": "src/mywidgets/mywindow.h",
    "content": "#ifndef MYWINDOW_H\r\n#define MYWINDOW_H\r\n\r\n#include <QObject>\r\n#include <QQuickWindow>\r\n#include <QPoint>\r\n#include <QQuickItem>\r\n#include <QPixmap>\r\n#include <QQueue>\r\n\r\nclass MyWindow : public QQuickWindow\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QUrl windowIcon READ windowIcon WRITE setWindowIcon NOTIFY windowIconChanged)//状态栏图标\r\n    Q_PROPERTY(bool noBorder READ noBorder WRITE setNoBorder NOTIFY noBorderIconChanged)//无边框\r\n    Q_PROPERTY(WindowStatus windowStatus READ windowStatus WRITE setWindowStatus NOTIFY windowStatusChanged)//窗口状态\r\n    Q_PROPERTY(int borderLeft READ borderLeft CONSTANT)//离屏幕左边的距离\r\n    Q_PROPERTY(int borderRight READ borderRight CONSTANT)//离屏幕右边的距离\r\n    Q_PROPERTY(int borderTop READ borderTop CONSTANT)//离屏幕上边的距离\r\n    Q_PROPERTY(bool topHint READ topHint WRITE setTopHint NOTIFY topHintChanged)//窗体保持在最前端\r\n    Q_PROPERTY(bool noNotifyIcon READ noNotifyIcon WRITE setNoNotifyIcon NOTIFY noNotifyIconChanged)//无状态栏图标\r\n    Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)//窗口的width（不包含边框的阴影）\r\n    Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)//窗口的height（不包含边框的阴影）\r\n    Q_PROPERTY(int actualWidth READ actualWidth WRITE setActualWidth NOTIFY actualWidthChanged)//真实的width，包含阴影\r\n    Q_PROPERTY(int actualHeight READ actualHeight WRITE setActualHeight NOTIFY actualHeightChanged)//真实的height，包含阴影\r\n    Q_PROPERTY(int x READ x WRITE setX NOTIFY xChanged)//窗口内容相对于桌面的绝对坐标（不包含阴影部分）\r\n    Q_PROPERTY(int y READ y WRITE setY NOTIFY yChanged)//窗口内容相对于桌面的绝对坐标（不包含阴影部分）\r\n    Q_PROPERTY(int actualX READ actualX WRITE setActualX NOTIFY actualXChanged)//窗口相对于桌面的绝对坐标（包含阴影部分）\r\n    Q_PROPERTY(int actualY READ actualY WRITE setActualY NOTIFY actualYChanged)//窗口相对于桌面的绝对坐标（包含阴影部分）\r\n    Q_PROPERTY(bool windowActive READ windowActive NOTIFY windowActiveChanged FINAL)//窗口是否获得焦点，是否为活跃窗口\r\n    Q_PROPERTY(int minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged)\r\n    Q_PROPERTY(int minimumHeight READ minimumHeight WRITE setMinimumHeight NOTIFY minimumHeightChanged)\r\n    Q_PROPERTY(int maximumWidth READ maximumWidth WRITE setMaximumWidth NOTIFY maximumWidthChanged)\r\n    Q_PROPERTY(int maximumHeight READ maximumHeight WRITE setMaximumHeight NOTIFY maximumHeightChanged)\r\n    Q_PROPERTY(bool mousePenetrate READ mousePenetrate WRITE setMousePenetrate NOTIFY mousePenetrateChanged)\r\n    //是否穿透鼠标\r\n    Q_PROPERTY(QPoint cursorPos READ cursorPos WRITE setCursorPos FINAL)\r\n    Q_ENUMS(WindowStatus)\r\npublic:\r\n    explicit MyWindow(QQuickWindow *parent = 0);\r\n    enum WindowStatus{\r\n        StopCenter,//初始状态,停在屏幕中，不靠任何边界\r\n        BerthPrepare,//进入准停靠状态（此时鼠标离开窗体就会停靠）\r\n        BerthLeft,//停靠在左边\r\n        BerthRight,//停靠在右边\r\n        BerthTop//停靠在上边\r\n    };\r\n    \r\n    QUrl windowIcon();\r\n    bool noNotifyIcon() const;\r\n    int width() const;\r\n    int height() const;\r\n    int actualWidth() const;\r\n    int actualHeight() const;\r\n    bool windowActive() const;\r\n    int x() const;\r\n    int y() const;\r\n    int actualX() const;\r\n    int actualY() const;\r\n    int minimumWidth() const;\r\n    int minimumHeight() const;\r\n    int maximumWidth() const;\r\n    int maximumHeight() const;\r\n    WindowStatus windowStatus();\r\n    bool noBorder();\r\n    int borderLeft();\r\n    int borderRight();\r\n    int borderTop();\r\n    \r\n    bool topHint() const;\r\n    bool mousePenetrate() const;\r\n    QPoint cursorPos() const;\r\n\r\nprivate:\r\n    QUrl m_windowIcon;\r\n    bool m_noBorder;\r\n    WindowStatus m_windowStatus;\r\n    bool m_topHint, old_topHint;\r\n    bool m_noNotifyIcon;\r\n    qreal m_width;\r\n    qreal m_height;\r\n    bool m_windowActive;\r\n    int m_minimumWidth;\r\n    int m_minimumHeight;\r\n    int m_maximumWidth;\r\n    int m_maximumHeight;\r\n    bool m_mousePenetrate;\r\n    \r\n    void setWindowActive(bool arg);\r\n\r\nprotected:\r\n    void focusInEvent(QFocusEvent * ev);\r\n    void focusOutEvent(QFocusEvent * ev);\r\nprivate slots:\r\n    void onActualXChanged();\r\n    void onActualYChanged();\r\n\r\nsignals:\r\n    void windowIconChanged();\r\n    void noBorderIconChanged();\r\n    void windowStatusChanged();\r\n    void topHintChanged(bool arg);\r\n    void noNotifyIconChanged(bool arg);\r\n    \r\n    void widthChanged(int arg);\r\n    void heightChanged(int arg);\r\n    void actualWidthChanged(int arg);\r\n    void actualHeightChanged(int arg);\r\n    void windowActiveChanged(bool arg);\r\n   \r\n    void xChanged();\r\n    void yChanged();\r\n    void actualXChanged(int arg);\r\n    void actualYChanged(int arg);\r\n    void minimumWidthChanged(int arg);\r\n    void minimumHeightChanged(int arg);\r\n    void maximumWidthChanged(int arg);\r\n    void maximumHeightChanged(int arg);\r\n    \r\n    void mousePenetrateChanged(bool arg);\r\n    void closeing();//当调用close时发射;\r\npublic slots:\r\n    void setNoBorder( bool isNoBroder );\r\n    void setWindowIcon( QUrl icon );\r\n    void setWindowStatus( WindowStatus new_status );\r\n    void setTopHint(bool arg);\r\n    void setNoNotifyIcon(bool arg);\r\n    void setWidth(int arg);\r\n    void setHeight(int arg);\r\n    void setActualWidth(int arg);\r\n    void setActualHeight(int arg);\r\n    void setX(int arg);\r\n    void setY(int arg);\r\n    void setActualX(int arg);\r\n    void setActualY(int arg);\r\n    void setMinimumWidth(int arg);\r\n    void setMinimumHeight(int arg);\r\n    void setMaximumWidth(int arg);\r\n    void setMaximumHeight(int arg);\r\n    void setMousePenetrate(bool arg);\r\n    void setCursorPos(QPoint cursorPos);\r\n    void setMousePenetrateArea(QRect rect);\r\n    \r\n    void close();\r\n    void deleteWindow();\r\n};\r\n\r\n#endif // MYWINDOW_H\r\n"
  },
  {
    "path": "src/mywidgets/systemtrayicon.cpp",
    "content": "#include \"systemtrayicon.h\"\r\n#include <QDebug>\r\n#include <QKeySequence>\r\n#include <QFile>\r\n#include \"utility.h\"\r\n#include \"qxtglobalshortcut.h\"\r\n\r\nSystemTrayIcon::SystemTrayIcon(QQuickItem *parent) :\r\n    QQuickItem(parent)\r\n{\r\n    setVisible (false);\r\n    systempTray = new QSystemTrayIcon(this);\r\n    connect (systempTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(onActivated(QSystemTrayIcon::ActivationReason)));\r\n    connect (systempTray, SIGNAL(messageClicked()), this, SIGNAL(messageClicked()));\r\n    connect (this, SIGNAL(visibleChanged()), SLOT(onVisibleChanged()));\r\n}\r\n\r\nvoid SystemTrayIcon::onActivated(QSystemTrayIcon::ActivationReason reason)\r\n{\r\n    emit activated (ActivationReason(reason));\r\n}\r\n\r\nvoid SystemTrayIcon::onVisibleChanged()\r\n{\r\n    systempTray->setVisible (isVisible ());\r\n}\r\n\r\nMyMenu *SystemTrayIcon::menu() const\r\n{\r\n    return m_menu;\r\n}\r\n\r\nQUrl SystemTrayIcon::windowIcon() const\r\n{\r\n    return m_windowIcon;\r\n}\r\n\r\nQString SystemTrayIcon::toolTip() const\r\n{\r\n    return m_toolTip;\r\n}\r\n\r\nint SystemTrayIcon::x() const\r\n{\r\n    return systempTray->geometry ().x ();\r\n}\r\nint SystemTrayIcon::y() const\r\n{\r\n    return systempTray->geometry ().y ();\r\n}\r\n\r\nint SystemTrayIcon::width() const\r\n{\r\n    return systempTray->geometry ().width ();\r\n}\r\n\r\nint SystemTrayIcon::height() const\r\n{\r\n    return systempTray->geometry ().height ();\r\n}\r\nvoid SystemTrayIcon::setWindowIcon(QUrl icon)\r\n{\r\n    if( icon!=m_windowIcon ){\r\n        QString str = icon.toLocalFile();\r\n        if(str == \"\"){\r\n            str = icon.toString();\r\n        }\r\n\r\n        if( str.mid (0, 3) == \"qrc\")\r\n            str = str.mid (3, str.count ()-3);\r\n        systempTray->setIcon (QIcon(str));\r\n        m_windowIcon = icon;\r\n        emit windowIconChanged ();\r\n    }\r\n}\r\n\r\nvoid SystemTrayIcon::showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon icon, int millisecondsTimeoutHint)\r\n{\r\n    systempTray->showMessage (title, message, icon, millisecondsTimeoutHint);\r\n}\r\n\r\nvoid SystemTrayIcon::setMenu(MyMenu *arg)\r\n{\r\n    if (m_menu != arg) {\r\n        m_menu = arg;\r\n        systempTray->setContextMenu (m_menu->menu);\r\n        emit menuChanged(arg);\r\n    }\r\n}\r\n\r\nvoid SystemTrayIcon::setToolTip(QString arg)\r\n{\r\n    if (m_toolTip != arg) {\r\n        m_toolTip = arg;\r\n        systempTray->setToolTip (arg);\r\n        emit toolTipChanged(arg);\r\n    }\r\n}\r\n\r\nMyMenuItem::MyMenuItem(QObject *parent) : \r\n    QAction(parent)\r\n{\r\n    setObjectName (\"MyMenuItem\");\r\n    m_shortcut = new QxtGlobalShortcut();\r\n    connect(m_shortcut, SIGNAL(activated()), SLOT(trigger()));\r\n}\r\n\r\nQUrl MyMenuItem::icon() const\r\n{\r\n    return m_myIcon;\r\n}\r\nQString MyMenuItem::shortcut() const\r\n{\r\n    return m_shortcut->shortcut ().toString ();\r\n}\r\n\r\nvoid MyMenuItem::setIcon(QUrl icon)\r\n{\r\n    if( icon!=m_myIcon ){\r\n        QString str = icon.toLocalFile();\r\n        if(str == \"\"){\r\n            str = icon.toString();\r\n        }\r\n\r\n        if( str.mid (0, 3) == \"qrc\")\r\n            str = str.mid (3, str.count ()-3);\r\n        QAction::setIcon (QIcon(str));\r\n        m_myIcon = icon;\r\n        emit iconChanged ();\r\n    }\r\n}\r\n\r\nvoid MyMenuItem::setShortcut(const QString &shortcut)\r\n{\r\n    if( m_shortcut->setShortcut (QKeySequence(shortcut)) ){\r\n        QAction::setShortcut (QKeySequence(shortcut));\r\n        emit shortcutChanged (shortcut);\r\n    }else{\r\n        qDebug()<<\"设置\"+shortcut+\"热键出错\";\r\n        emit shortcutChanged (\"set shortcut error\");\r\n    }\r\n}\r\n\r\nvoid MyMenu::componentComplete()\r\n{\r\n    QObjectList temp_list = children ();\r\n    for (int i=0; i<temp_list.count (); ++i) {\r\n        QObject *obj = temp_list.at (i);\r\n        if( obj->objectName ()==\"MyMenuItem\"){\r\n            MyMenuItem *item = qobject_cast<MyMenuItem*>(obj);\r\n            menu->addAction(item);\r\n        }else if(obj->objectName ()==\"MenuSeparator\"){\r\n            menu->addSeparator ();\r\n        }else if(obj->objectName ()==\"MyMenu\"){\r\n            MyMenu *item = qobject_cast<MyMenu*>(obj);\r\n            menu->addMenu (item->menu);\r\n        }\r\n    }\r\n}\r\n\r\nMyMenu::MyMenu(QQuickItem *parent) : \r\n    QQuickItem(parent)\r\n{\r\n    m_styleSource = QUrl(\"\");\r\n    setObjectName (\"MyMenu\");\r\n    menu = new MenuPrivate();\r\n    setVisible (false);\r\n}\r\n\r\nQUrl MyMenu::styleSource() const\r\n{\r\n    return m_styleSource;\r\n}\r\n\r\nint MyMenu::width() const\r\n{\r\n    return menu->width ();\r\n}\r\n\r\nint MyMenu::height() const\r\n{\r\n    return menu->height ();\r\n}\r\n\r\nQString MyMenu::styleSheet() const\r\n{\r\n    return menu->styleSheet ();\r\n}\r\n\r\nvoid MyMenu::clear()\r\n{\r\n    menu->clear ();\r\n}\r\n\r\nvoid MyMenu::addSeparator()\r\n{\r\n    menu->addSeparator ();\r\n}\r\n\r\nvoid MyMenu::addMenuItem(MyMenuItem *item)\r\n{\r\n    menu->addAction(item);\r\n}\r\n\r\nvoid MyMenu::addMenu(MyMenu *mymenu)\r\n{\r\n    menu->addMenu (mymenu->menu);\r\n}\r\n\r\nvoid MyMenu::setStyleSource(QUrl arg)\r\n{\r\n    if (m_styleSource != arg) {\r\n        m_styleSource = arg;\r\n\r\n        QString str = arg.toLocalFile();\r\n        if(str == \"\"){\r\n            str = arg.toString();\r\n            if(str==\"\"){\r\n                return;\r\n            }\r\n        }\r\n\r\n        if( str.mid (0, 3) == \"qrc\")\r\n            str = str.mid (3, str.count ()-3);\r\n\r\n        QFile file(str);\r\n        \r\n        if(file.open (QIODevice::ReadOnly)){\r\n            menu->setStyleSheet (file.readAll ());\r\n        }else{\r\n            qDebug()<<\"打开\"+str+\"失败；\"<<file.errorString ();\r\n        }\r\n        file.close ();\r\n        emit styleSourceChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyMenu::popup()\r\n{\r\n    QPoint pos = Utility::createUtilityClass ()->mouseDesktopPos();\r\n    menu->move (pos);\r\n    menu->show ();\r\n}\r\n\r\nvoid MyMenu::setWidth(int arg)\r\n{\r\n    int m_width = menu->width ();\r\n    if (m_width != arg) {\r\n        menu->setFixedWidth (arg);\r\n        emit widthChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyMenu::setHeight(int arg)\r\n{\r\n    int m_height = menu->height ();\r\n    if (m_height != arg) {\r\n        menu->setFixedHeight (arg);\r\n        emit heightChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyMenu::setStyleSheet(QString arg)\r\n{\r\n    QString m_styleSheet = menu->styleSheet ();\r\n    if (m_styleSheet != arg) {\r\n        menu->setStyleSheet (arg);\r\n        emit styleSheetChanged(arg);\r\n    }\r\n}\r\n\r\n\r\nMenuSeparator::MenuSeparator(QObject *parent):\r\n    QObject(parent)\r\n{\r\n    setObjectName (\"MenuSeparator\");\r\n}\r\n\r\nMenuPrivate::MenuPrivate(QWidget *parent):\r\n    QMenu(parent)\r\n{\r\n}\r\n\r\nMenuPrivate::MenuPrivate(const QString &title, QWidget *parent):\r\n    QMenu(title, parent)\r\n{\r\n}\r\n"
  },
  {
    "path": "src/mywidgets/systemtrayicon.h",
    "content": "#ifndef SYSTEMTRAYICON_H\r\n#define SYSTEMTRAYICON_H\r\n\r\n#include <QSystemTrayIcon>\r\n#include <QUrl>\r\n#include <QMenu>\r\n#include <QAction>\r\n#include <QQuickItem>\r\n#include <QShortcut>\r\n\r\nclass QxtGlobalShortcut;\r\nclass MenuPrivate: public QMenu\r\n{\r\n    Q_OBJECT\r\npublic:\r\n    explicit MenuPrivate(QWidget *parent = 0);\r\n    explicit MenuPrivate(const QString &title, QWidget *parent = 0);\r\n};\r\n\r\nclass MyMenuItem : public QAction\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QUrl icon READ icon WRITE setIcon NOTIFY iconChanged)\r\n    Q_PROPERTY(QString shortcut READ shortcut WRITE setShortcut NOTIFY shortcutChanged)\r\n    QUrl m_myIcon;\r\n    QxtGlobalShortcut* m_shortcut;\r\npublic:\r\n    explicit MyMenuItem(QObject *parent = 0);\r\n    QUrl icon() const;\r\n    QString shortcut() const;\r\npublic slots:\r\n    void setIcon(QUrl icon);\r\n    void setShortcut(const QString &shortcut);\r\nsignals:\r\n    void iconChanged();\r\n    void shortcutChanged(QString arg);\r\n};\r\n\r\nclass MenuSeparator : public QObject\r\n{\r\npublic:\r\n    explicit MenuSeparator(QObject *parent=0);\r\n};\r\n\r\nclass SystemTrayIcon;\r\nclass MyMenu : public QQuickItem\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QUrl styleSource READ styleSource WRITE setStyleSource NOTIFY styleSourceChanged)\r\n    Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet NOTIFY styleSheetChanged)\r\n    Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)\r\n    Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)\r\n\r\n    MenuPrivate *menu;\r\n    QUrl m_styleSource;\r\n    \r\nprotected:\r\n    void componentComplete();    \r\npublic:\r\n    explicit MyMenu(QQuickItem *parent = 0);\r\n    \r\n    QUrl styleSource() const;\r\n    int width() const;\r\n    int height() const;\r\n    QString styleSheet() const;\r\npublic slots:\r\n    void clear();\r\n    void addSeparator ();\r\n    void addMenuItem(MyMenuItem *item);\r\n    void addMenu( MyMenu *mymenu);\r\n    friend class SystemTrayIcon;\r\n    void setStyleSource(QUrl arg);\r\n    \r\n    void popup();\r\n    void setWidth(int arg);\r\n    void setHeight(int arg);\r\n    void setStyleSheet(QString arg);\r\nsignals:\r\n    void styleSourceChanged(QUrl arg);\r\n    void widthChanged(int arg);\r\n    void heightChanged(int arg);\r\n    void styleSheetChanged(QString arg);\r\n};\r\n\r\nclass SystemTrayIcon : public QQuickItem\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QUrl windowIcon READ windowIcon WRITE setWindowIcon NOTIFY windowIconChanged)\r\n    Q_PROPERTY(MyMenu* menu READ menu WRITE setMenu NOTIFY menuChanged)\r\n    Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip NOTIFY toolTipChanged)\r\n    Q_PROPERTY(int x READ x CONSTANT)\r\n    Q_PROPERTY(int y READ y CONSTANT)\r\n    Q_PROPERTY(int width READ width CONSTANT)\r\n    Q_PROPERTY(int height READ height CONSTANT)\r\n    Q_ENUMS(ActivationReason)\r\n    QUrl m_windowIcon;\r\n    MyMenu* m_menu;\r\n    QSystemTrayIcon *systempTray;\r\n    QString m_toolTip;\r\nprotected:\r\n    \r\npublic:\r\n    explicit SystemTrayIcon(QQuickItem *parent = 0);\r\n    QUrl windowIcon() const;\r\n    \r\n    enum ActivationReason {\r\n        Unknown,\r\n        Context,\r\n        DoubleClick,\r\n        Trigger,\r\n        MiddleClick\r\n    };\r\n    \r\n    QString toolTip() const;\r\n    int x() const;\r\n    int y() const;\r\n    int width() const;\r\n    int height() const;\r\nprivate slots:\r\n    void onActivated( QSystemTrayIcon::ActivationReason reason );\r\n    void onVisibleChanged();\r\n    MyMenu* menu() const;\r\n\r\nsignals:\r\n    void windowIconChanged();\r\n    void menuChanged(MyMenu* arg);\r\n    void activated(ActivationReason arg);\r\n    void toolTipChanged(QString arg);\r\n    void messageClicked();\r\npublic slots:\r\n    void setWindowIcon(QUrl icon);\r\n    void showMessage(const QString & title, const QString & message, QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int millisecondsTimeoutHint = 10000);\r\n    void setMenu(MyMenu* arg);\r\n    void setToolTip(QString arg);\r\n};\r\n\r\n#endif // SYSTEMTRAYICON_H\r\n"
  },
  {
    "path": "src/qqstars/qqiteminfo.cpp",
    "content": "#include \"qqiteminfo.h\"\r\n#include \"utility.h\"\r\n#include \"qqstars.h\"\r\n\r\nQString ChatMessageInfo::senderUin() const\r\n{\r\n    return m_senderUin;\r\n}\r\n\r\nQString ChatMessageInfo::contentData() const\r\n{\r\n    return m_contentData;\r\n}\r\n\r\nQDate ChatMessageInfo::date() const\r\n{\r\n    return m_date;\r\n}\r\n\r\nQTime ChatMessageInfo::time() const\r\n{\r\n    return m_time;\r\n}\r\n\r\nint ChatMessageInfo::messageId() const\r\n{\r\n    return m_messageId;\r\n}\r\n\r\nint ChatMessageInfo::messageId2() const\r\n{\r\n    return m_messageId2;\r\n}\r\n\r\nconst QQItemInfo *ChatMessageInfo::getParent()\r\n{\r\n    return qobject_cast<QQItemInfo *>(parent());\r\n}\r\n\r\nChatMessageInfo::ChatMessageInfo(QQItemInfo *parent)\r\n{\r\n    ChatMessageInfo(-1, parent);\r\n}\r\n\r\nChatMessageInfo::ChatMessageInfo(int messageID, QQItemInfo *parent):\r\n    QObject(parent)\r\n{\r\n    m_messageId=messageID;\r\n}\r\n\r\nvoid ChatMessageInfo::setSenderUin(QString arg)\r\n{\r\n    if (m_senderUin == arg)\r\n        return;\r\n    \r\n    m_senderUin = arg;\r\n    emit senderUinChanged(arg);\r\n}\r\n\r\nvoid ChatMessageInfo::setContentData(QString arg)\r\n{\r\n    if (m_contentData == arg)\r\n        return;\r\n    \r\n    m_contentData = arg;\r\n    emit contentDataChanged(arg);\r\n}\r\n\r\nvoid ChatMessageInfo::setDate(QDate arg)\r\n{\r\n    if (m_date == arg)\r\n        return;\r\n    \r\n    m_date = arg;\r\n    emit dateChanged(arg);\r\n}\r\n\r\nvoid ChatMessageInfo::setTime(QTime arg)\r\n{\r\n    if (m_time == arg)\r\n        return;\r\n    \r\n    m_time = arg;\r\n    emit timeChanged(arg);\r\n}\r\n\r\nvoid ChatMessageInfo::setMessageId2(int arg)\r\n{\r\n    if (m_messageId2 != arg) {\r\n        m_messageId2 = arg;\r\n        emit messageId2Changed(arg);\r\n    }\r\n}\r\n\r\nQSqlDatabase DatabaseOperation::sqlite_db;\r\nDatabaseOperation *DatabaseOperation::createDatabaseOperation()\r\n{\r\n    static DatabaseOperation me;\r\n    return &me;\r\n}\r\n\r\nDatabaseOperation::DatabaseOperation():\r\n    QObject(0)\r\n{\r\n    if (!sqlite_db.isValid()){//如果数据库无效，则进行初始化\r\n        sqlite_db = QSqlDatabase::addDatabase (\"QSQLITE\");\r\n    }\r\n}\r\n\r\nDatabaseOperation::~DatabaseOperation()\r\n{\r\n    closeSqlDatabase();//关闭数据库\r\n}\r\n\r\nbool DatabaseOperation::tableAvailable(const QString &tableName)\r\n{\r\n    if(tableName!=\"\"&&sqlite_db.isOpen ()){//如果数据库已经打开\r\n        QString temp = \"create table if not exists \"+tableName+\r\n                \"(myindex INTEGER,senderUin VARCHAR[16],message TEXT,mydate DATE,mytime TIME)\";\r\n        //创建一个表，如果这表不存在，表的列为uin message mydate mytime\r\n        QSqlQuery query = sqlite_db.exec (temp);\r\n        if(query.lastError ().type ()==QSqlError::NoError){//如果上面的语句执行没有出错\r\n            return true;\r\n        }else{\r\n            qDebug()<<\"执行\"<<temp<<\"出错：\"<<query.lastError ().text ();\r\n        }\r\n    }else{\r\n        qDebug()<<\"数据库未打开\";\r\n    }\r\n    return false;\r\n}\r\n\r\nbool DatabaseOperation::openSqlDatabase(const QString& userqq)\r\n{\r\n    //emit sql_open (userqq);//发送信号打开数据库\r\n    if(!sqlite_db.isOpen ()){//如果数据库未打开\r\n        //sqlite_db = QSqlDatabase::addDatabase(\"QSQLITE\");\r\n        sqlite_db.setHostName (\"localhost\");\r\n        QString name = QDir::homePath ()+\"/.webqq/\"+userqq+\"/.QQData.db\";\r\n        sqlite_db.setDatabaseName (name);\r\n        sqlite_db.setUserName (\"雨后星辰\");\r\n        sqlite_db.setPassword (\"XingChenQQ\");\r\n        \r\n        return sqlite_db.open ();\r\n    }\r\n    return true;\r\n}\r\n\r\nvoid DatabaseOperation::closeSqlDatabase()\r\n{\r\n    sqlite_db.close ();\r\n}\r\n\r\nvoid DatabaseOperation::insertData(const QString& tableName, ChatMessageInfo *data)\r\n{\r\n    if(tableAvailable (tableName)){//判断表是否可以操作\r\n        QString temp = \"insert into \"+tableName+\r\n                \" values(:myindex,:senderUin,:message,:mydate,:mytime)\";\r\n        QSqlQuery insert_query;\r\n        insert_query.prepare (temp);\r\n        int index = sqlite_db.exec (\"select count(*) from \"+tableName).size ()+1;//设置此条数据的索引值\r\n        Utility *utility = Utility::createUtilityClass ();\r\n        insert_query.bindValue (\":myindex\", index);//设置数据的索引值（为此条数据的唯一标识）\r\n        insert_query.bindValue (\":senderUin\", data->senderUin ());\r\n        insert_query.bindValue (\":message\", utility->stringEncrypt (data->contentData (), \"XingchenQQ123\"));\r\n        //将contentData加密后储存\r\n        insert_query.bindValue (\":mydate\", data->date());\r\n        insert_query.bindValue (\":mytime\", data->time());\r\n        if(insert_query.exec ()){//如果上面的语句执行没有出错\r\n            //qDebug()<<\"插入数据成功\";\r\n        }else{\r\n            qDebug()<<\"执行\"<<temp<<\"出错：\"<<insert_query.lastError ().text ();\r\n        }\r\n    }\r\n}\r\n\r\nvoid DatabaseOperation::insertDatas(const QString &tableName, ChatMessageInfoList* datas)\r\n{\r\n    //emit sql_insertDatas (tableName, datas);\r\n    if(tableAvailable (tableName)){//判断表是否可以操作\r\n        sqlite_db.transaction ();//开启事务操作\r\n        for (int i=0;i<datas->size ();++i) {\r\n            ChatMessageInfo* data = datas->at (i);\r\n            if(data!=NULL){\r\n                insertData (tableName, data);\r\n            }\r\n        }\r\n        if(sqlite_db.commit ()){//提交事务操作,如果上面的语句执行没有出错\r\n            qDebug()<<\"插入\"+QString::number (datas->size ())+\"条数据成功\";\r\n        }else{\r\n            qDebug()<<\"执行多条插入出错：\"<<sqlite_db.lastError ().text ();\r\n        }\r\n    }\r\n}\r\n\r\nvoid DatabaseOperation::getDatas(const QString &tableName, int count, ChatMessageInfo *currentData, ChatMessageInfoList* datas)\r\n{\r\n    //emit sql_getDatas (tableName, count, currentData, datas);\r\n    if(tableAvailable (tableName)){//判断表是否可以操作\r\n        QString sql_code = \"select myindex from \"+tableName\r\n                +\"where senderUin=\"+currentData->senderUin ()\r\n                +\" and message=\"+currentData->contentData ()\r\n                +\" and mydate=\"+currentData->date().toString ()\r\n                +\" and mytime=\"+currentData->time().toString ();\r\n        QSqlQuery sql_query = sqlite_db.exec (sql_code);\r\n        if(sql_query.lastError ().type ()==QSqlError::NoError){//如果查询没有出错\r\n            if(sql_query.size ()>0){\r\n                int currentIndex = sql_query.value (0).toInt ();//当前数据的索引为\r\n                sql_code = \"select * from \"+tableName\r\n                        +\"where myindex<\"+QString::number (currentIndex)\r\n                        +\" and myindex<=\"+QString::number (currentIndex+count);\r\n                sql_query.exec (sql_code);\r\n                if(sql_query.lastError ().type ()==QSqlError::NoError){//如果查询没有出错\r\n                    qDebug()<<\"查询多条数据完成，数据的个数：\"<<sql_query.size ();\r\n                    while(sql_query.next ()){\r\n                        ChatMessageInfo *data = new ChatMessageInfo;\r\n                        Utility *utility = Utility::createUtilityClass ();\r\n                        data->setSenderUin (sql_query.value (1).toString ());//从第一个开始，因为0为index\r\n                        data->setContentData (utility->stringUncrypt (sql_query.value (2).toString (), \"XingchenQQ123\"));\r\n                        //取回聊天内容时要解密\r\n                        data->setDate (QDate::fromString (sql_query.value (3).toString ()));\r\n                        data->setTime (QTime::fromString (sql_query.value (4).toString ()));\r\n                        datas->append (data);//将查询到的结果添加到列表中\r\n                    }\r\n                    //emit getDatasFinished (datas);//发送信号，告知数据获取完成\r\n                }else{\r\n                    qDebug()<<\"执行\"<<sql_code<<\"出错：\"<<sql_query.lastError ().text ();\r\n                }\r\n            }else{\r\n                qDebug()<<\"执行\"<<sql_code<<\"未查询到结果\";\r\n            }\r\n        }else{\r\n            qDebug()<<\"执行\"<<sql_code<<\"出错：\"<<sql_query.lastError ().text ();\r\n        }\r\n    }\r\n}\r\n\r\nQQItemInfo::QQItemInfo(QQItemInfo::QQItemType type, QObject *parent):\r\n    QObject(parent), m_mytype (type)\r\n{\r\n    m_uin = \"\";\r\n    m_account = \"\";\r\n    m_aliasOrNick = \"\";\r\n    m_userQQ = \"\";\r\n    m_nick = \"\";\r\n    m_alias = \"\";\r\n    m_unreadMessagesCount = 0;\r\n    messageID = 0;\r\n    max_chatMessage_count=100;//最多在内存中保存100条聊天记录\r\n    \r\n    queue_chatRecords = new ChatMessageInfoList(this);\r\n    \r\n    connect (this, &QQItemInfo::settingsChanged, this, &QQItemInfo::avatar40Changed);\r\n    connect (this, &QQItemInfo::settingsChanged, this, &QQItemInfo::avatar240Changed);\r\n    connect (this, &QQItemInfo::nickChanged, this, &QQItemInfo::updataAliasOrNick);\r\n    connect (this, &QQItemInfo::aliasChanged, this, &QQItemInfo::updataAliasOrNick);\r\n    connect (this, &QQItemInfo::isActiveChatPageChanged, this, &QQItemInfo::clearUnreadMessages);\r\n    \r\n    typeString = typeToString (type);\r\n}\r\n\r\nQQItemInfo::QQItemInfo(QObject *)\r\n{\r\n    return;\r\n}\r\n\r\nQQItemInfo::~QQItemInfo()\r\n{\r\n    queue_chatRecords->clear ();//清除内存中的聊天记录\r\n}\r\n\r\nvoid QQItemInfo::initSettings()\r\n{\r\n    QString userqq = userQQ ();\r\n    QString account = this->account ();\r\n    \r\n    if(account==\"\"||userqq==\"\")\r\n        return;\r\n    QString name = QDir::homePath ()+\"/.webqq/\"+userqq+\"/\"+typeString+\"_\"+account+\"/.config.ini\";\r\n    //qDebug()<<\"设置了QSettings为\"<<name;\r\n    if(mysettings){\r\n        //qDebug()<<mysettings->fileName ();\r\n        if(mysettings->fileName ()==name)\r\n            return;\r\n        mysettings->deleteLater ();\r\n    }\r\n    mysettings = new QSettings(name, QSettings::IniFormat);\r\n    emit settingsChanged ();\r\n}\r\n\r\nbool QQItemInfo::isCanUseSetting() const\r\n{\r\n    return (mytype()!=Discu&&userQQ()!=\"\"&&account()!=\"\"&&mysettings);\r\n}\r\n\r\nvoid QQItemInfo::removeOldChatRecord()\r\n{\r\n    queue_chatRecords->dequeue ()->deleteLater ();//销毁最老的那条消息\r\n}\r\n\r\nQString QQItemInfo::uin() const\r\n{\r\n    return m_uin;\r\n}\r\n\r\nQString QQItemInfo::nick() const\r\n{\r\n    return m_nick;\r\n}\r\n\r\nQString QQItemInfo::alias() const\r\n{\r\n    return m_alias;\r\n}\r\n\r\n\r\nQString QQItemInfo::avatar40() const\r\n{\r\n    if(isCanUseSetting()){\r\n        QString temp_str =  mysettings->value (\"avatar-40\", \"qrc:/images/avatar.png\").toString ();\r\n        if(temp_str.left(3)!=\"qrc\")\r\n            temp_str = \"file:///\"+temp_str;\r\n\r\n        return temp_str;\r\n    }\r\n    return \"qrc:/images/avatar.png\";\r\n}\r\n\r\nQString QQItemInfo::avatar240() const\r\n{\r\n    if(isCanUseSetting()){\r\n        QString temp_str =  mysettings->value (\"avatar-240\", \"qrc:/images/avatar.png\").toString ();\r\n        if(temp_str.left(3)!=\"qrc\")\r\n            temp_str = \"file:///\"+temp_str;\r\n\r\n        return temp_str;\r\n    }\r\n    return \"qrc:/images/avatar.png\";\r\n}\r\n\r\nQString QQItemInfo::aliasOrNick()\r\n{\r\n    QString m_alias = alias();\r\n    if(m_alias!=\"\")\r\n        return m_alias;\r\n    return nick ();\r\n}\r\n\r\nQString QQItemInfo::userQQ() const\r\n{\r\n    return m_userQQ;\r\n}\r\n\r\nQString QQItemInfo::typeToString()\r\n{\r\n    return typeString;\r\n}\r\n\r\nconst QString QQItemInfo::typeToString(QQItemInfo::QQItemType type)\r\n{\r\n    switch (type) {\r\n    case Friend:\r\n        return \"Friend\";\r\n        break;\r\n    case Group:\r\n        return \"Group\";\r\n    case Discu:\r\n        return \"Discu\";\r\n    default:\r\n        return \"\";\r\n    }\r\n}\r\n\r\nconst QString QQItemInfo::localCachePath(QQItemInfo::QQItemType type, const QString &userqq, const QString &account)\r\n{\r\n    QString typeString = typeToString (type);\r\n    return QDir::homePath ()+\"/.webqq/\"+userqq+\"/\"+typeString+\"_\"+account;\r\n}\r\n\r\nQQItemInfo::QQItemType QQItemInfo::mytype() const\r\n{\r\n    return m_mytype;\r\n}\r\n\r\nint QQItemInfo::unreadMessagesCount() const\r\n{\r\n    return m_unreadMessagesCount;\r\n}\r\n\r\nbool QQItemInfo::isActiveChatPage() const\r\n{\r\n    return m_isActiveChatPage;\r\n}\r\n\r\nQString QQItemInfo::account() const\r\n{\r\n    return m_account;\r\n}\r\n\r\nvoid QQItemInfo::setUin(QString arg)\r\n{\r\n    if (m_uin != arg) {\r\n        m_uin = arg;\r\n        if(mytype ()==Discu)//如果是讨论组\r\n            setAccount (arg);//讨论组无真实qq，所以用uin充当\r\n        emit uinChanged ();\r\n        setIsActiveChatPage (false);//默认为false\r\n    }\r\n}\r\n\r\nvoid QQItemInfo::setNick(QString arg)\r\n{\r\n    if (m_nick != arg) {\r\n        m_nick = arg;\r\n        emit nickChanged ();\r\n    }\r\n}\r\n\r\nvoid QQItemInfo::setAlias(QString arg)\r\n{\r\n    if(m_alias!=arg){\r\n        m_alias = arg;\r\n        emit aliasChanged();\r\n    }\r\n}\r\n\r\nvoid QQItemInfo::setAccount(QString arg)\r\n{\r\n    if (m_account != arg) {\r\n        m_account = arg;\r\n        initSettings();\r\n        emit accountChanged();\r\n    }\r\n}\r\n\r\nvoid QQItemInfo::setAvatar40(QString arg)\r\n{\r\n    if(isCanUseSetting ()){\r\n        mysettings->setValue (\"avatar-40\", arg);\r\n        emit avatar40Changed();\r\n    }\r\n}\r\n\r\nvoid QQItemInfo::setAvatar240(QString arg)\r\n{\r\n    if(isCanUseSetting ()){\r\n        mysettings->setValue (\"avatar-240\", arg);\r\n        emit avatar240Changed();\r\n    }\r\n}\r\n\r\nvoid QQItemInfo::updataAliasOrNick()\r\n{\r\n    QString arg = aliasOrNick ();\r\n    if (m_aliasOrNick != arg) {\r\n        m_aliasOrNick = arg;\r\n        emit aliasOrNickChanged();\r\n    }\r\n}\r\n\r\nvoid QQItemInfo::setUserQQ(QString arg)\r\n{\r\n    if(m_userQQ!=arg) {\r\n        m_userQQ = arg;\r\n        initSettings();\r\n        emit userQQChanged ();\r\n    }\r\n}\r\n\r\nvoid QQItemInfo::clearSettings()\r\n{\r\n    if(isCanUseSetting()){\r\n        mysettings->clear ();//清除所有储存的信息\r\n        qDebug()<<mysettings->fileName ()<<\"清除成功\";\r\n    }\r\n}\r\n\r\nconst QString QQItemInfo::localCachePath() const\r\n{\r\n    return QDir::homePath ()+\"/.webqq/\"+userQQ()+\"/\"+typeString+\"_\"+account();\r\n}\r\n\r\nChatMessageInfoList *QQItemInfo::getChatRecords()\r\n{\r\n    clearUnreadMessages();//将未读消息清空\r\n    return queue_chatRecords;//返回所有消息\r\n}\r\n\r\nvoid QQItemInfo::addChatRecord(ChatMessageInfo *data)\r\n{\r\n    if(data!=NULL){\r\n        queue_chatRecords->append (data);//将此条记录加到队列当中\r\n        //qDebug()<<\"现在缓冲区中消息的条数为：\"<<queue_chatRecords->size ();\r\n        if(queue_chatRecords->size ()>max_chatMessage_count){\r\n            removeOldChatRecord ();//移除最老的那条消息\r\n        }\r\n        QQCommand* command = QQCommand::getFirstQQCommand ();\r\n        if(data->senderUin ()!=command->uin ()&&!isActiveChatPage ()){\r\n            //如果发送人不是自己（意思是这条消息不是你发给别人的，而是收到的），并且聊天页面不是活跃的，\r\n            setUnreadMessagesCount (unreadMessagesCount ()+1);//增加未读消息的个数\r\n        }\r\n        command->addRecentContacts (this);//将自己添加到最近联系人列表\r\n    }\r\n}\r\n\r\nvoid QQItemInfo::clearUnreadMessages()\r\n{\r\n    setUnreadMessagesCount (0);\r\n}\r\n\r\nvoid QQItemInfo::setIsActiveChatPage(bool arg)\r\n{\r\n    if (m_isActiveChatPage != arg) {\r\n        m_isActiveChatPage = arg;\r\n        emit isActiveChatPageChanged(arg);\r\n    }\r\n}\r\n\r\nChatMessageInfo *QQItemInfo::getChatMessageInfoById(int messageID)\r\n{\r\n    ChatMessageInfo* info = queue_chatRecords->find (messageID);//先查找这条消息是否存在\r\n    if(info==NULL){//为空证明没有找到\r\n        info = new ChatMessageInfo(messageID, this);\r\n    }\r\n    return info;\r\n}\r\n\r\nint QQItemInfo::getMessageIndex()\r\n{\r\n    return messageID++;\r\n}\r\n\r\nvoid QQItemInfo::setUnreadMessagesCount(int arg)\r\n{\r\n    if (m_unreadMessagesCount != arg) {\r\n        m_unreadMessagesCount = arg;\r\n        emit unreadMessagesCountChanged(arg);\r\n    }\r\n}\r\n\r\nFriendInfo::FriendInfo(QObject *parent):\r\n    QQItemInfo(Friend, parent)\r\n{\r\n    m_signature = \"\";\r\n    m_state = Offline;\r\n    m_stateToString = \"offline\";\r\n    max_chatMessage_count=150;//最大缓存消息数量\r\n    saveRecord_coount=50;//一次将50条消息记录插入到本地（不能大于max_chatMessage_count）\r\n    \r\n    connect (this, &QQItemInfo::settingsChanged, this, &FriendInfo::onSettingsChanged);\r\n    //链接信号，处理settings对象改变的信号\r\n    getChatRecordsing=false;//记录现在是否在请求获取聊天记录\r\n    itemInfoPrivate = DatabaseOperation::createDatabaseOperation ();\r\n}\r\n\r\nFriendInfo::~FriendInfo()\r\n{\r\n    saveChatMessageToLocal ();//销毁此对象之前不要忘记将聊天记录存起来\r\n}\r\n\r\nQString FriendInfo::QQSignature()\r\n{\r\n    return m_signature;\r\n}\r\n\r\nFriendInfo::States FriendInfo::state() const\r\n{\r\n    return m_state;\r\n}\r\n\r\nQString FriendInfo::stateToString() const\r\n{\r\n    return m_stateToString;\r\n}\r\n\r\nvoid FriendInfo::removeOldChatRecord()\r\n{\r\n    ChatMessageInfoList list;\r\n    for(int i=0;i<saveRecord_coount;++i){\r\n        list.append (queue_chatRecords->dequeue ());\r\n    }\r\n    QString tableName = \"table_\"+typeToString ()+account();\r\n    itemInfoPrivate->insertDatas (tableName, &list);\r\n    list.clear ();//保存后记得清空\r\n}\r\n\r\nvoid FriendInfo::onSettingsChanged()\r\n{\r\n    if(QQSignature ()==\"\"){//如果个性签名为空\r\n        QString temp = mysettings->value (\"signature\", \"\").toString ();\r\n        if(temp!=\"\"){\r\n            setQQSignature (temp);\r\n        }else{//如果获得的个性签名为空，就发送信号在qml端去网络获取个性签名\r\n            emit httpGetQQSignature();//发送信号\r\n        }\r\n    }\r\n}\r\n\r\nvoid FriendInfo::setQQSignature(QString arg)\r\n{\r\n    if (m_signature != arg) {\r\n        m_signature = arg;\r\n        if(isCanUseSetting ())//如果可以储存配置信息\r\n            mysettings->setValue (\"signature\", arg);\r\n        emit qQSignatureChanged();\r\n    }\r\n}\r\n\r\nvoid FriendInfo::openSqlDatabase(const QString &userqq)\r\n{\r\n    if(!itemInfoPrivate->openSqlDatabase (userqq)){\r\n        qDebug()<<\"FriendInfo:数据库打开失败！\";\r\n    }\r\n}\r\n\r\nvoid FriendInfo::closeSqlDatabase()\r\n{\r\n    itemInfoPrivate->closeSqlDatabase ();\r\n}\r\n\r\nvoid FriendInfo::saveChatMessageToLocal()\r\n{\r\n    if(account ()!=\"\"){//qq账户（qq号码）一定不能为空，因为它是消息发送者的唯一标识\r\n        QString tableName = \"table_\"+typeToString ()+account();\r\n        itemInfoPrivate->insertDatas (tableName, queue_chatRecords);//将所有聊天记录保存下来\r\n        //将内存中的消息添加到数据库\r\n    }\r\n}\r\n\r\nvoid FriendInfo::setState(FriendInfo::States arg)\r\n{\r\n    if (m_state != arg) {\r\n        m_state = arg;\r\n        switch(arg)\r\n        {\r\n        case Online:\r\n            m_stateToString = \"online\";\r\n            break;\r\n        case Callme:\r\n            m_stateToString = \"callme\";\r\n            break;\r\n        case Away:\r\n            m_stateToString = \"away\";\r\n            break;\r\n        case Busy:\r\n            m_stateToString = \"busy\";\r\n            break;\r\n        case Silent:\r\n            m_stateToString = \"silent\";\r\n            break;\r\n        case Hidden:\r\n            m_stateToString = \"hidden\";\r\n            break;\r\n        case Offline:\r\n            m_stateToString = \"offline\";\r\n            break;\r\n        default:break;\r\n        }\r\n        emit stateChanged(arg);\r\n        emit stateToStringChanged (m_stateToString);\r\n    }\r\n}\r\n\r\nvoid FriendInfo::setStateToString(const QString &str)\r\n{\r\n    if(str!=m_stateToString){\r\n        if(str==\"online\"){\r\n            setState (Online);\r\n        }else if(str==\"callme\"){\r\n            setState (Callme);\r\n        }else if(str==\"away\"){\r\n            setState (Away);\r\n        }else if(str==\"busy\"){\r\n            setState (Busy);\r\n        }else if(str==\"silent\"){\r\n            setState (Silent);\r\n        }else if(str==\"hidden\"){\r\n            setState (Hidden);\r\n        }else if(str==\"offline\"){\r\n            setState (Offline);\r\n        }\r\n    }\r\n}\r\n\r\nvoid FriendInfo::saveChatMessageToLocal(ChatMessageInfo* data)\r\n{\r\n    if(account ()!=\"\"){//qq账户（qq号码）一定不能为空，因为它是消息发送者的唯一标识\r\n        QString tableName = \"table_\"+typeToString ()+account();\r\n        itemInfoPrivate->insertData (tableName, data);\r\n    }\r\n}\r\n\r\nvoid FriendInfo::getLocalChatRecords(ChatMessageInfo *currentData, int count)\r\n{\r\n    if(account ()!=\"\"&&!getChatRecordsing){//qq账户（qq号码）一定不能为空，因为它是消息发送者的唯一标识\r\n        QString tableName = \"table_\"+typeToString ()+account();\r\n        getChatRecordsing = true;//将此值置为true\r\n        ChatMessageInfoList list;\r\n        itemInfoPrivate->getDatas (tableName, count, currentData, &list);\r\n        //开始获取聊天记录\r\n        for(int i=0;i<list.size ();++i){\r\n            queue_chatRecords->insert (i, list.at (i));\r\n        }\r\n    }\r\n}\r\n\r\nGroupInfo::GroupInfo(QObject *parent):\r\n    QQItemInfo(Group, parent)\r\n{\r\n    m_code = \"\";\r\n}\r\n\r\nQString GroupInfo::code() const\r\n{\r\n    return m_code;\r\n}\r\n\r\nint GroupInfo::membersCount() const\r\n{\r\n    return queue_members.count ();\r\n}\r\n\r\nQString GroupInfo::announcement() const\r\n{\r\n    return m_announcement;\r\n}\r\n\r\nvoid GroupInfo::setCode(QString arg)\r\n{\r\n    if (m_code == arg)\r\n        return;\r\n    \r\n    m_code = arg;\r\n    emit codeChanged(arg);\r\n}\r\n\r\nvoid GroupInfo::addMember(FriendInfo *info)\r\n{\r\n    if(!queue_members.contains (info)){//如果不存在\r\n        queue_members<<info;\r\n        emit memberCountChanged (queue_members.count ());\r\n        emit memberIncrease (info);\r\n    }else{\r\n        qDebug()<<\"GroupInfo:要增加的群成员已经存在\"<<info;\r\n    }\r\n}\r\n\r\nvoid GroupInfo::removeMemberByUin(const QString &uin)\r\n{\r\n    for (int i=0;i<queue_members.count ();++i) {\r\n        FriendInfo* info = queue_members[i];\r\n        if(info&&info->uin ()==uin){\r\n            queue_members.removeAt (i);\r\n            emit memberCountChanged (queue_members.count ());\r\n            emit memberReduce (i);\r\n            break;\r\n        }\r\n    }\r\n}\r\n\r\nvoid GroupInfo::removeMemberByInfo(const FriendInfo *info)\r\n{\r\n    for (int i=0;i<queue_members.count ();++i) {\r\n        FriendInfo* temp_info = queue_members[i];\r\n        if(temp_info==info){\r\n            queue_members.removeAt (i);\r\n            emit memberCountChanged (queue_members.count ());\r\n            emit memberReduce (i);\r\n            break;\r\n        }\r\n    }\r\n}\r\n\r\nvoid GroupInfo::setMemberCard(const QString &uin, const QString &card)\r\n{\r\n    map_card[uin]=card;\r\n}\r\n\r\nQString GroupInfo::getMemberCardByUin(const QString &uin, const QString &defaultCard)\r\n{\r\n    return map_card.value (uin, defaultCard);\r\n}\r\n\r\nFriendInfo *GroupInfo::getMemberInfoByIndex(int index)\r\n{\r\n    return queue_members[index];\r\n}\r\n\r\nvoid GroupInfo::setAnnouncement(QString arg)\r\n{\r\n    if (m_announcement == arg)\r\n        return;\r\n    \r\n    m_announcement = arg;\r\n    emit announcementChanged(arg);\r\n}\r\n\r\nDiscuInfo::DiscuInfo(QObject *parent):\r\n    QQItemInfo(Discu, parent)\r\n{\r\n}\r\n\r\nvoid DiscuInfo::addMember(FriendInfo *info)\r\n{\r\n    if(!queue_members.contains (info)){//如果不存在\r\n        queue_members<<info;\r\n        emit memberCountChanged (queue_members.count ());\r\n        emit memberIncrease (info);\r\n    }\r\n}\r\n\r\nvoid DiscuInfo::removeMemberByUin(const QString &uin)\r\n{\r\n    for (int i=0;i<queue_members.count ();++i) {\r\n        FriendInfo* info = queue_members[i];\r\n        if(info&&info->uin ()==uin){\r\n            queue_members.removeOne (info);\r\n            emit memberCountChanged (queue_members.count ());\r\n            emit memberReduce (i);\r\n            break;\r\n        }\r\n    }\r\n}\r\n\r\nvoid DiscuInfo::removeMemberByInfo(const FriendInfo *info)\r\n{\r\n    for (int i=0;i<queue_members.count ();++i) {\r\n        FriendInfo* temp_info = queue_members[i];\r\n        if(temp_info==info){\r\n            queue_members.removeAt (i);\r\n            emit memberCountChanged (queue_members.count ());\r\n            break;\r\n        }\r\n    }\r\n}\r\n\r\nint DiscuInfo::membersCount() const\r\n{\r\n    return queue_members.count ();\r\n}\r\n\r\nFriendInfo *DiscuInfo::getMemberInfoByIndex(int index)\r\n{\r\n    return queue_members[index];\r\n}\r\n\r\nRecentInfo::RecentInfo(FriendInfo *info, QObject *parent):\r\n    QObject(parent)\r\n{\r\n    setInfoData (info);\r\n    setInfoToFriend (info);\r\n}\r\n\r\nRecentInfo::RecentInfo(GroupInfo *info, QObject *parent):\r\n    QObject(parent)\r\n{\r\n    setInfoData (info);\r\n    setInfoToGroup (info);\r\n}\r\n\r\nRecentInfo::RecentInfo(DiscuInfo *info, QObject *parent):\r\n    QObject(parent)\r\n{\r\n    setInfoData (info);\r\n    setInfoToDiscu (info);\r\n}\r\n\r\nQObject *RecentInfo::infoData() const\r\n{\r\n    return m_infoData;\r\n}\r\n\r\nFriendInfo *RecentInfo::infoToFriend() const\r\n{\r\n    return m_infoToFriend;\r\n}\r\n\r\nGroupInfo *RecentInfo::infoToGroup() const\r\n{\r\n    return m_infoToGroup;\r\n}\r\n\r\nDiscuInfo *RecentInfo::infoToDiscu() const\r\n{\r\n    return m_infoToDiscu;\r\n}\r\n\r\nvoid RecentInfo::setInfoToFriend(FriendInfo *arg)\r\n{\r\n    if (m_infoToFriend != arg) {\r\n        m_infoToFriend = arg;\r\n        emit infoToFriendChanged(arg);\r\n    }\r\n}\r\n\r\nvoid RecentInfo::setInfoToGroup(GroupInfo *arg)\r\n{\r\n    if (m_infoToGroup != arg) {\r\n        m_infoToGroup = arg;\r\n        emit infoToGroupChanged(arg);\r\n    }\r\n}\r\n\r\nvoid RecentInfo::setInfoToDiscu(DiscuInfo *arg)\r\n{\r\n    if (m_infoToDiscu != arg) {\r\n        m_infoToDiscu = arg;\r\n        emit infoToDiscuChanged(arg);\r\n    }\r\n}\r\n\r\nvoid RecentInfo::setInfoData(QObject *info)\r\n{\r\n    m_infoData = info;\r\n    emit infoDataChanged ();\r\n}\r\n\r\nChatMessageInfoList::ChatMessageInfoList(QObject *parent):\r\n    QObject(parent)\r\n{\r\n}\r\n\r\nChatMessageInfo *ChatMessageInfoList::at(int i)\r\n{\r\n    return list.at (i);\r\n}\r\n\r\nint ChatMessageInfoList::length()\r\n{\r\n    return list.length ();\r\n}\r\n\r\nint ChatMessageInfoList::size()\r\n{\r\n    return length();\r\n}\r\n\r\nvoid ChatMessageInfoList::append(ChatMessageInfo *obj)\r\n{\r\n    list<<obj;\r\n}\r\n\r\nvoid ChatMessageInfoList::insert(int pos, ChatMessageInfo *obj)\r\n{\r\n    list.insert (pos, obj);\r\n}\r\n\r\nvoid ChatMessageInfoList::destroy()\r\n{\r\n    clear();//先清除\r\n    this->deleteLater ();\r\n}\r\n\r\nvoid ChatMessageInfoList::clear()\r\n{\r\n    foreach (ChatMessageInfo* info, list) {\r\n        if(info!=NULL){\r\n            info->deleteLater ();//销毁这条消息\r\n        }\r\n    }\r\n    list.clear ();//清空list;\r\n}\r\n\r\nChatMessageInfo *ChatMessageInfoList::dequeue()\r\n{\r\n    return list.dequeue ();\r\n}\r\n\r\nChatMessageInfo* ChatMessageInfoList::find(int messageID)\r\n{\r\n    foreach (ChatMessageInfo* info, list) {\r\n        if(info!=NULL&&info->messageId ()==messageID)\r\n            return info;\r\n    }\r\n    return NULL;\r\n}\r\n"
  },
  {
    "path": "src/qqstars/qqiteminfo.h",
    "content": "#ifndef QQITEMINFO_H\r\n#define QQITEMINFO_H\r\n\r\n#include <QtSql>\r\n#include <QSettings>\r\n#include <QObject>\r\n#include <QDate>\r\n#include <QTime>\r\n#include <QQueue>\r\n#include <QThread>\r\n#include <QPointer>\r\n#include <QTimer>\r\n#include <QString>\r\n#include <QDir>\r\n\r\nclass QQItemInfo;\r\nclass ChatMessageInfo:public QObject//用来储存聊天消息的各种信息\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QString senderUin READ senderUin WRITE setSenderUin NOTIFY senderUinChanged)//储存发送人的uin\r\n    Q_PROPERTY(QString contentData READ contentData WRITE setContentData NOTIFY contentDataChanged)//储存消息内容\r\n    Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged)//储存收到此条信息的日期\r\n    Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged)//储存收到此条信息的时间\r\n    Q_PROPERTY(int messageId READ messageId)\r\n    Q_PROPERTY(int messageId2 READ messageId2 WRITE setMessageId2 NOTIFY messageId2Changed)\r\n    \r\npublic:\r\n    ChatMessageInfo(QQItemInfo* parent=0);\r\n    ChatMessageInfo(int messageID, QQItemInfo* parent);\r\n    \r\n    QString senderUin() const;\r\n    QString contentData() const;\r\n    QDate date() const;\r\n    QTime time() const;\r\n    int messageId() const;\r\n    int messageId2() const;\r\n    const QQItemInfo* getParent();//获取此条消息所属的ItemInfo对象\r\nprivate:\r\n    QString m_senderUin;\r\n    QString m_contentData;\r\n    QDate m_date;\r\n    QTime m_time;\r\n    int m_messageId;\r\n    int m_messageId2;\r\n    \r\nsignals:\r\n    void senderUinChanged(QString arg);\r\n    void contentDataChanged(QString arg);\r\n    void dateChanged(QDate arg);\r\n    void timeChanged(QTime arg);\r\n    void messageId2Changed(int arg);\r\n\r\npublic slots:\r\n    void setSenderUin(QString arg);\r\n    void setContentData(QString arg);\r\n    void setDate(QDate arg);\r\n    void setTime(QTime arg);\r\n    void setMessageId2(int arg);\r\n};\r\n\r\nclass ChatMessageInfoList:public QObject\r\n{\r\n    Q_OBJECT\r\npublic:\r\n    ChatMessageInfoList(QObject* parent=0);\r\nprivate:\r\n    QQueue<ChatMessageInfo*> list;\r\npublic slots:\r\n    ChatMessageInfo* at(int i);\r\n    int length();\r\n    int size();\r\n    void append( ChatMessageInfo *obj);\r\n    void insert(int pos, ChatMessageInfo *obj);\r\n    void destroy();\r\n    void clear();//清除储存的聊天记录\r\n    ChatMessageInfo* dequeue();//出队\r\n    ChatMessageInfo *find(int messageID);\r\n};\r\n\r\nclass DatabaseOperation:public QObject//提供数据库的操作（用于储存聊天记录）\r\n{\r\n    Q_OBJECT\r\npublic:\r\n    static DatabaseOperation* createDatabaseOperation();\r\nprivate:\r\n    static QSqlDatabase sqlite_db;\r\n    DatabaseOperation();\r\n    ~DatabaseOperation();\r\n    bool tableAvailable(const QString& tableName);//判断表名为tableName的表是可操作\r\n\r\npublic slots:\r\n    bool openSqlDatabase(const QString& userqq);//初始化数据库\r\n    void closeSqlDatabase();\r\n    void insertData(const QString& tableName, ChatMessageInfo *data);//向数据库中插入数据\r\n    void insertDatas(const QString& tableName, ChatMessageInfoList *datas);//向数据库中插入多条数据\r\n    void getDatas(const QString& tableName, int count, ChatMessageInfo* currentData, ChatMessageInfoList *datas);\r\n    //获取数据库中的count条数据，将获得的数据存入datas当中\r\n};\r\n\r\nclass QQItemInfo:public QObject\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QString userQQ READ userQQ WRITE setUserQQ NOTIFY userQQChanged)\r\n    Q_PROPERTY(QString uin READ uin WRITE setUin NOTIFY uinChanged)\r\n    Q_PROPERTY(QString nick READ nick WRITE setNick NOTIFY nickChanged)\r\n    Q_PROPERTY(QString alias READ alias WRITE setAlias NOTIFY aliasChanged)\r\n    Q_PROPERTY(QString aliasOrNick READ aliasOrNick NOTIFY aliasOrNickChanged FINAL)\r\n    Q_PROPERTY(QString avatar40 READ avatar40 WRITE setAvatar40 NOTIFY avatar40Changed)\r\n    Q_PROPERTY(QString avatar240 READ avatar240 WRITE setAvatar240 NOTIFY avatar240Changed)\r\n    Q_PROPERTY(QString account READ account WRITE setAccount NOTIFY accountChanged)\r\n    Q_PROPERTY(int unreadMessagesCount READ unreadMessagesCount NOTIFY unreadMessagesCountChanged FINAL)//未读消息的条数\r\n    Q_PROPERTY(QQItemType mytype READ mytype NOTIFY mytypeChanged FINAL)\r\n    Q_PROPERTY(bool isActiveChatPage READ isActiveChatPage WRITE setIsActiveChatPage NOTIFY isActiveChatPageChanged)\r\n    \r\n    Q_ENUMS(QQItemType)\r\n    friend class FriendInfo;\r\n    friend class GroupInfo;\r\n    friend class DiscuInfo;\r\n    friend class RecentInfo;\r\npublic:\r\n    explicit QQItemInfo(QObject *parent=0);\r\n    ~QQItemInfo();\r\n    enum QQItemType{\r\n        Friend,//好友\r\n        Group,//群\r\n        Discu//讨论组\r\n    };\r\n    \r\nprivate:\r\n    explicit QQItemInfo(QQItemType type, QObject *parent=0);\r\n    void initSettings();\r\n    void setUnreadMessagesCount(int arg);//设置未读消息的个数\r\n    \r\n    QString m_uin;//uin，为此qq的唯一标识\r\n    QString m_account;//qq账号\r\n    QString m_aliasOrNick;\r\n    QString m_userQQ;\r\n    QString m_nick;//储存昵称\r\n    QString m_alias;\r\n    QString typeString;\r\n    int m_unreadMessagesCount;\r\n    QQItemType m_mytype;\r\n    bool m_isActiveChatPage;\r\n    int messageID;//为自己个好友发送的消息的id（为此消息的唯一标识）\r\nprotected:\r\n    ChatMessageInfoList* queue_chatRecords;//储存聊天记录的队列\r\n    QPointer<QSettings> mysettings;\r\n    int max_chatMessage_count;//在queue_chatRecords中最多保存多少条聊天记录\r\n    \r\n    bool isCanUseSetting() const;//是否可以调用settings\r\n    virtual void removeOldChatRecord();//将最老的那条消息清除\r\npublic:\r\n    static const QString typeToString(QQItemType type);\r\n    static const QString localCachePath(QQItemType type, const QString& userqq, const QString& account);//本地缓存路径\r\n    QString uin() const;\r\n    QString nick() const;\r\n    QString alias() const;\r\n    QString avatarSource() const;\r\n    QString account() const;\r\n    QString avatar40() const;\r\n    QString avatar240() const;\r\n    QString aliasOrNick();\r\n    QString userQQ() const;\r\n    QString typeToString();\r\n    QQItemType mytype() const;\r\n    int unreadMessagesCount() const;\r\n    bool isActiveChatPage() const;\r\n    \r\nprivate slots:\r\n    void updataAliasOrNick();\r\n    void clearUnreadMessages();//清空未读消息\r\npublic slots:\r\n    void setUin(QString arg);\r\n    void setNick(QString arg);\r\n    void setAlias(QString arg);\r\n    void setAccount(QString arg);\r\n    void setAvatar40(QString arg);\r\n    void setAvatar240(QString arg);\r\n    void setUserQQ(QString arg);\r\n    void clearSettings();//清除配置信息\r\n    const QString localCachePath() const;//本地缓存路径\r\n    ChatMessageInfoList *getChatRecords();//将内存中的聊天记录读回\r\n    void addChatRecord(ChatMessageInfo *data);//增加聊天记录，记录在内存当中\r\n    void setIsActiveChatPage(bool arg);\r\n    ChatMessageInfo* getChatMessageInfoById(int messageID);//通过messageID返回一个储存聊天记录的信息的对象\r\n    int getMessageIndex();//返回一个本次在线中的一个唯一的数字，用于收到或者发送的消息的id\r\n    \r\nsignals:\r\n    void nickChanged();\r\n    void aliasChanged();\r\n    void accountChanged();\r\n    void avatar40Changed();\r\n    void avatar240Changed();\r\n    void aliasOrNickChanged();\r\n    void userQQChanged();\r\n    void uinChanged();\r\n    void settingsChanged();\r\n    void mytypeChanged(QQItemType arg);\r\n    void unreadMessagesCountChanged(int arg);\r\n    void isActiveChatPageChanged(bool arg);\r\n};\r\n\r\nclass FriendInfo:public  QQItemInfo\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QString QQSignature READ QQSignature WRITE setQQSignature NOTIFY qQSignatureChanged)//个性签名\r\n    Q_PROPERTY(States state READ state WRITE setState NOTIFY stateChanged)\r\n    Q_PROPERTY(QString stateToString READ stateToString WRITE setStateToString NOTIFY stateToStringChanged)\r\n    Q_ENUMS(States)\r\npublic:\r\n    explicit FriendInfo(QObject *parent=0);\r\n    ~FriendInfo();\r\n    QString QQSignature();\r\n    \r\n    enum States{//登录后的用户的qq状态\r\n        Offline,//离线中\r\n        Online,//在线\r\n        Callme,//Q我吧\r\n        Away,//离开\r\n        Busy,//忙碌\r\n        Silent,//请勿打扰\r\n        Hidden//隐身\r\n    };\r\n    States state() const;\r\n    QString stateToString() const;\r\n    \r\nprivate:\r\n    QString m_signature;//用来储存个性签名\r\n    DatabaseOperation *itemInfoPrivate;//里边定义了数据库的操作，用来储存聊天记录\r\n    bool getChatRecordsing;//记录现在是否正在请求获取本地聊天记录\r\n    States m_state;\r\n    QString m_stateToString;\r\n    int saveRecord_coount;//记录一次插入多少条聊天记录到数据库\r\n    \r\n    void removeOldChatRecord();//当消息数量超过最大缓存量时被调用\r\nprotected slots:\r\n    virtual void onSettingsChanged();//处理settings对象改变的信号\r\npublic slots:\r\n    void setQQSignature(QString arg);\r\n    void openSqlDatabase(const QString &userqq);//初始化数据库\r\n    void closeSqlDatabase();\r\n    void getLocalChatRecords(ChatMessageInfo *currentData, int count);//读取本地聊天记录（从数据库）\r\n    void saveChatMessageToLocal(ChatMessageInfo *data);//将此消息记录保存到到本地（保存到数据库中）\r\n    void saveChatMessageToLocal();//将当前内存中的消息记录保存到到本地（保存到数据库中）\r\n    void setState(States arg);\r\n    void setStateToString(const QString &str);\r\nsignals:\r\n    void qQSignatureChanged();\r\n    void httpGetQQSignature();//发送信号告诉qml端去获取个性签名\r\n    void stateChanged(States arg);\r\n    void stateToStringChanged(QString arg);\r\n};\r\n\r\nclass GroupInfo:public  QQItemInfo\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QString code READ code WRITE setCode NOTIFY codeChanged)//相当于好友的uin的功能\r\n    Q_PROPERTY(int membersCount READ membersCount NOTIFY memberCountChanged FINAL)//群成员个数\r\n    Q_PROPERTY(QString announcement READ announcement WRITE setAnnouncement NOTIFY announcementChanged)\r\n    \r\n    QString m_code;\r\n    QQueue<FriendInfo*> queue_members;//储存群成员列表\r\n    QMap<QString, QString> map_card;\r\n    QString m_announcement;\r\n\r\npublic:\r\n    explicit GroupInfo(QObject *parent=0);\r\n    QString code() const;\r\n    int membersCount() const;\r\n    QString announcement() const;\r\n    \r\npublic slots:\r\n    void setCode(QString arg);\r\n    void addMember(FriendInfo* info);//增加群成员\r\n    void removeMemberByUin(const QString& uin);//删除群成员（根据uin）\r\n    void removeMemberByInfo(const FriendInfo *info);//删除群成员（根据uin）\r\n    void setMemberCard(const QString& uin, const QString& card);//给群成员设置群名片\r\n    QString getMemberCardByUin(const QString& uin, const QString& defaultCard);\r\n    FriendInfo* getMemberInfoByIndex(int index);//获取群成员信息\r\n    void setAnnouncement(QString arg);\r\nsignals:\r\n    void codeChanged(QString arg);\r\n    void memberCountChanged(int arg);\r\n    void memberIncrease(FriendInfo* info);//群成员增加了\r\n    void memberReduce(int index);//群成员减少了,index为被移除的群成员序号\r\n    void announcementChanged(QString arg);\r\n};\r\n\r\nclass DiscuInfo:public  QQItemInfo\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(int membersCount READ membersCount NOTIFY memberCountChanged FINAL)//讨论组成员个数\r\n    \r\n    QQueue<FriendInfo*> queue_members;//储存讨论组成员列表\r\npublic:\r\n    explicit DiscuInfo(QObject *parent=0);\r\n    int membersCount() const;\r\npublic slots:\r\n    void addMember(FriendInfo* info);//增加群成员\r\n    void removeMemberByUin(const QString& uin);//删除群成员（根据uin）\r\n    void removeMemberByInfo(const FriendInfo *info);//删除群成员（根据uin）\r\n    FriendInfo* getMemberInfoByIndex(int index);//获取讨论组成员信息\r\nsignals:\r\n    void memberCountChanged(int arg);\r\n    void memberIncrease(FriendInfo* info);//群成员增加了\r\n    void memberReduce(int index);//群成员减少了,index为被移除的群成员序号\r\n};\r\n\r\nclass RecentInfo:public  QObject\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QObject* infoData READ infoData NOTIFY infoDataChanged FINAL)\r\n    Q_PROPERTY(FriendInfo* infoToFriend READ infoToFriend NOTIFY infoToFriendChanged FINAL)\r\n    Q_PROPERTY(GroupInfo* infoToGroup READ infoToGroup NOTIFY infoToGroupChanged FINAL)\r\n    Q_PROPERTY(DiscuInfo* infoToDiscu READ infoToDiscu NOTIFY infoToDiscuChanged FINAL)\r\npublic:\r\n    //explicit RecentInfo(QQuickItem *parent=0);\r\n    explicit RecentInfo(FriendInfo *info, QObject *parent=0);\r\n    explicit RecentInfo(GroupInfo *info, QObject *parent=0);\r\n    explicit RecentInfo(DiscuInfo *info, QObject *parent=0);\r\n    QObject* infoData() const;\r\n    FriendInfo* infoToFriend() const;\r\n    GroupInfo* infoToGroup() const;\r\n    DiscuInfo* infoToDiscu() const;\r\nsignals:\r\n    void infoDataChanged();\r\n    void infoToFriendChanged(FriendInfo* arg);\r\n    void infoToGroupChanged(GroupInfo* arg);\r\n    void infoToDiscuChanged(DiscuInfo* arg);\r\nprivate:\r\n    void setInfoData(QObject* info);\r\n    void setInfoToFriend(FriendInfo* arg);\r\n    void setInfoToGroup(GroupInfo* arg);\r\n    void setInfoToDiscu(DiscuInfo* arg);\r\n    QPointer<QObject> m_infoData;\r\n    QPointer<FriendInfo> m_infoToFriend;\r\n    QPointer<GroupInfo> m_infoToGroup;\r\n    QPointer<DiscuInfo> m_infoToDiscu;\r\n};\r\n\r\n#endif // QQITEMINFO_H\r\n"
  },
  {
    "path": "src/qqstars/qqstars.cpp",
    "content": "#include \"qqstars.h\"\r\n#include \"utility.h\"\r\n#include <QJsonDocument>\r\n#include <QSettings>\r\n#include \"mywindow.h\"\r\n#include \"myhttprequest.h\"\r\n#include \"mymessagebox.h\"\r\n#include \"mynetworkaccessmanagerfactory.h\"\r\n\r\nQQCommand *QQCommand::firstQQCommand = NULL;\r\nQQCommand *QQCommand::getFirstQQCommand()\r\n{\r\n    return firstQQCommand;\r\n}\r\n\r\nQQCommand::QQCommand( QObject *parent) :\r\n    FriendInfo(parent)\r\n{\r\n    if(firstQQCommand==NULL)\r\n        firstQQCommand = this;\r\n    connect (this, &FriendInfo::stateChanged, this, &QQCommand::onStateChanged);\r\n    \r\n    Utility *utility=Utility::createUtilityClass ();\r\n    int temp1 = utility->value (\"proxyType\", QNetworkProxy::NoProxy).toInt ();\r\n    QString temp2 = utility->value (\"proxyLocation\", \"\").toString ();\r\n    QString temp3 = utility->value (\"proxyPort\", \"\").toString ();\r\n    QString temp4 = utility->value (\"proxyUsername\", \"\").toString ();\r\n    QString temp5 = utility->value (\"proxyPassword\", \"\").toString ();\r\n    utility->setApplicationProxy (temp1, temp2, temp3, temp4, temp5);\r\n    \r\n    setUserQQ (utility->value (\"mainqq\",\"\").toString ());\r\n    m_loginStatus = WaitLogin;//当前为离线(还未登录)\r\n    m_windowScale = 1;//缺省窗口比例为1\r\n    chatImageID = 0;//初始化为0\r\n    \r\n    request = new QNetworkRequest;\r\n    request->setUrl (QUrl(\"http://d.web2.qq.com/channel/poll2\"));\r\n    request->setRawHeader (\"Origin\", \"http://d.web2.qq.com\");\r\n    request->setRawHeader (\"Accept\", \"*/*\");\r\n    request->setRawHeader (\"Referer\", \"http://d.web2.qq.com/proxy.html?v=20110331002&callback=1&id=2\");\r\n    request->setRawHeader (\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n    request->setRawHeader (\"User-Agent\", \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36 LBBROWSER\");\r\n    \r\n    manager = new NetworkAccessManager(this);\r\n    connect (manager, SIGNAL(finished(QNetworkReply*)), SLOT(poll2Finished(QNetworkReply*)));\r\n    \r\n    jsEngine = new QJSEngine();//此对象用来加载js文件（为qq提供api）\r\n    loadApi ();//加载api的js文件\r\n    \r\n    reply = NULL;\r\n    poll2Timerout_count=0;//记录网络请求的连续超时次数\r\n    poll2Error_count=0;//记录网络请求连续出错的次数\r\n    connect (utility, &Utility::networkOnlineStateChanged, this, &QQCommand::onNetworkOnlineStateChanged);\r\n    poll2_timer = new QTimer(this);\r\n    poll2_timer->setSingleShot (true);//设置为单发射器\r\n    connect (poll2_timer, &QTimer::timeout, this, &QQCommand::onPoll2Timeout);\r\n    abortPoll_timer = new QTimer(this);\r\n    abortPoll_timer->setSingleShot (true);//设置为单发射器\r\n    \r\n    http_image = new MyHttpRequest(this);//此网络请求对象专门用来获取聊天中收到图片的真实下载地址\r\n    http_image->getNetworkRequest ()->setRawHeader (\r\n                \"Referer\", \"http://d.web2.qq.com/proxy.html?v=20110331002&callback=1&id=2\");//必须设置，不然请求腾讯的数据会返回出错\r\n}\r\n\r\nQQCommand::LoginStatus QQCommand::loginStatus() const\r\n{\r\n    return m_loginStatus;\r\n}\r\n\r\nQString QQCommand::userPassword() const\r\n{\r\n    return m_userPassword;\r\n}\r\n\r\ndouble QQCommand::windowScale() const\r\n{\r\n    return m_windowScale;\r\n}\r\n\r\nQString QQCommand::userQQ() const\r\n{\r\n    return m_userQQ;\r\n}\r\n\r\nbool QQCommand::rememberPassword() const\r\n{\r\n    if(isCanUseSetting())\r\n        return mysettings->value (\"rememberPassword\", false).toBool ();\r\n    return false;\r\n}\r\n\r\nbool QQCommand::autoLogin() const\r\n{\r\n    if(isCanUseSetting())\r\n        return mysettings->value (\"autoLogin\", false).toBool ();\r\n    return false;\r\n}\r\n\r\nQString QQCommand::codeText() const\r\n{\r\n    if(code_window){\r\n        return code_window->property (\"code\").toString ();\r\n    }\r\n    return \"\";\r\n}\r\n\r\nvoid QQCommand::beginPoll2()\r\n{\r\n    disconnect (abortPoll_timer, &QTimer::timeout, reply, &QNetworkReply::abort);\r\n    //qDebug()<<\"reply1:\"<<reply;\r\n    reply=manager->post (*request, poll2_data);\r\n    //qDebug()<<\"reply2:\"<<reply;\r\n    connect (abortPoll_timer, &QTimer::timeout, reply, &QNetworkReply::abort);\r\n    poll2_timer->start (100000);//网络请求超时定时器\r\n}\r\n\r\nvoid QQCommand::poll2Finished(QNetworkReply *replys)\r\n{\r\n    poll2_timer->stop ();//停止计算请求是否超时的计时器\r\n    if(replys->error ()==QNetworkReply::NoError) {\r\n        QByteArray array = replys->readAll ();\r\n        emit poll2ReData (array);\r\n        QJsonParseError json_error;\r\n        QJsonDocument document = QJsonDocument::fromJson (array, &json_error);\r\n        if(json_error.error == QJsonParseError::NoError) \r\n        {\r\n            if( document.isObject () ){\r\n                QJsonObject obj = document.object ();\r\n                if( obj[\"retcode\"].isDouble () ){\r\n                    int retcode = obj[\"retcode\"].toInt ();\r\n                    if( retcode==0 ){\r\n                        QJsonArray arr = obj[\"result\"].toArray ();\r\n                        foreach (QJsonValue temp, arr) {\r\n                            obj = temp.toObject ();\r\n                            QString poll_type=obj[\"poll_type\"].toString ();\r\n                            obj = obj[\"value\"].toObject ();\r\n                            if( poll_type==\"message\" ){\r\n                                disposeFriendMessage (obj);//解析好友的普通消息\r\n                            }else if( poll_type==\"input_notify\" ){\r\n                                disposeFriendMessage (obj, InputNotify);//解析好友正在输入的消息\r\n                            }else if( poll_type==\"buddies_status_change\" ){\r\n                                disposeFriendStatusChanged(obj);//好友状态改变信息\r\n                            }else if( poll_type==\"group_message\" ){\r\n                                disposeGroupMessage (obj);//解析群消息\r\n                            }else if( poll_type==\"discu_message\" ){\r\n                                disposeDiscuMessage (obj);//解析讨论组消息\r\n                            }else if( poll_type==\"file_message\" ){\r\n                                //qDebug()<<\"发送文件消息\";\r\n                                disposeFriendMessage (obj, FileMessage);\r\n                            }else if( poll_type==\"av_request\" ){\r\n                                //qDebug()<<\"视频聊天消息\";\r\n                                disposeFriendMessage (obj, AvRequest);\r\n                            }else if( poll_type==\"av_refuse\" ){\r\n                                //qDebug()<<\"取消开视频\";\r\n                                disposeFriendMessage (obj, AvRefuse);\r\n                            }else if( poll_type==\"shake_message\" ){\r\n                                //qDebug()<<\"窗口抖动消息\";\r\n                                disposeFriendMessage (obj, ShakeWindow);//解析窗口抖动消息\r\n                            }else if( poll_type==\"system_message\" ){\r\n                                disposeSystemMessage (obj);//解析系统消息\r\n                            }else if( poll_type==\"sys_g_msg\" ){\r\n                                disposeSystemMessage (obj);//解析系统消息\r\n                            }else if(poll_type == \"sess_message\"){\r\n                                //disposeStrangerMessage (obj);//解析陌生人的消息\r\n                                disposeFriendMessage (obj);//解析好友的普通消息\r\n                            }else{\r\n                                qDebug()<<\"QQCommand:其他消息\"<<poll_type;\r\n                            }\r\n                        }\r\n                        beginPoll2();\r\n                    }else if(retcode==102){\r\n                        beginPoll2();\r\n                    }else if(retcode==116){\r\n                        beginPoll2();\r\n                    }else{\r\n                        qDebug()<<\"QQCommand:qq已掉线，即将重新登录\";\r\n                        QMetaObject::invokeMethod (this, \"reLogin\");//调用槽reLogin（在qml中定义）\r\n                    }\r\n                }\r\n            }else if(document.isArray ()){\r\n                QJsonArray arr = document.array ();\r\n                qDebug()<<\"QQCommand:心跳包收到的是一个数组\"<<arr.count ();\r\n            }\r\n        }\r\n    }else if(replys->error ()!=QNetworkReply::OperationCanceledError){//如果不是手动取消的\r\n        ++poll2Error_count;\r\n        if(poll2Error_count>1){\r\n            qDebug()<<\"QQCommand:网络请求连续出错\"<<poll2Error_count<<\"次，将重新登录\";\r\n            poll2Error_count=0;\r\n            QMetaObject::invokeMethod (this, \"reLogin\");//调用槽reLogin重新登录（在qml中定义）\r\n        }else\r\n            beginPoll2();//重新post\r\n    }\r\n}\r\n\r\nvoid QQCommand::initUserPassword()\r\n{\r\n    if(isCanUseSetting()){\r\n        QString pass=mysettings->value (\"password\", \"\").toString ();\r\n        setUserPassword (Utility::createUtilityClass ()->stringUncrypt (pass, \"xingchenQQ\"));\r\n    }\r\n}\r\n\r\nvoid QQCommand::onChatMainWindowClose()//如果主聊天窗口关闭，那就销毁所有已经建立的聊天页面\r\n{\r\n    foreach (QQuickItem *item, map_chatPage) {\r\n        if(item!=NULL){\r\n            QString key = map_chatPage.key (item);\r\n            QString uin,typeStr;\r\n            for(int i=0;i<key.length ();++i){\r\n                if(key[i].isNumber ()){\r\n                    uin = key.mid (i);\r\n                    typeStr = key.mid (0,i);\r\n                    break;\r\n                }\r\n            }\r\n            item->deleteLater ();//销毁此页面\r\n        }\r\n    }\r\n    map_chatPage.clear ();//清空所有对象\r\n}\r\n\r\nvoid QQCommand::onSettingsChanged()\r\n{\r\n    emit rememberPasswordChanged ();\r\n    emit autoLoginChanged ();\r\n    initUserPassword ();\r\n    setState ((States)mysettings->value (\"myState\", (int)Online).toInt ());//设置自己的状态\r\n}\r\n\r\nvoid QQCommand::onStateChanged()\r\n{\r\n    mysettings->setValue (\"myState\", (int)state());\r\n}\r\n\r\nvoid QQCommand::onPoll2Timeout()\r\n{\r\n    ++poll2Timerout_count;//记录网络请求的连续超时次数\r\n    qDebug()<<\"QQCommand:网络请求超时：\"<<poll2Timerout_count;\r\n    if(reply){\r\n        reply->abort ();//取消网络请求\r\n    }\r\n    beginPoll2 ();//再次开始网络请求\r\n}\r\n\r\nvoid QQCommand::onNetworkOnlineStateChanged(bool isOnline)\r\n{\r\n    qDebug()<<\"QQCommand:网络在线状态改变为：\"<<isOnline;\r\n    if(isOnline){\r\n        abortPoll_timer->stop ();//停止计时器\r\n        if(!reply||!reply->isRunning ()){//如果心跳包没有在进行\r\n            qDebug()<<\"QQCommand:由于断网影响，将重新登录qq\";\r\n            QMetaObject::invokeMethod (this, \"reLogin\");//调用槽reLogin重新登录（在qml中定义）\r\n        }\r\n    }else{\r\n        abortPoll_timer->start (60000);//启动取消心跳包的定时器\r\n    }\r\n}\r\n\r\nvoid QQCommand::downImageFinished(DownloadImage::ErrorType error, const QString &path, const QString &name)\r\n{\r\n    QStringList list = name.split (\"_\");//分割字符串\r\n    QString rootUin=list[0];//图片发送者本身或者图片发送者所在群的uin\r\n    int messageID = list[1].toInt ();//分离出messageID\r\n    int imageID = list[2].toInt ();//分离出imageID\r\n    \r\n    QString senderType;\r\n    QRegExp reg(\"[A-Z][a-z]+_[0-9]+\");//符合条件的字符串，例如Friend_826169080\r\n    if(reg.indexIn (path)>=0){//如果找到了\r\n        senderType = reg.cap (0);\r\n        QStringList list = senderType.split (\"_\");\r\n        senderType=list[0];//图片所有者的类型（如果是好友发送的就是Friend，如果是群成员发送的就是Group）\r\n    }else{\r\n        qDebug()<<\"QQCommand:从下载路径中提取uin和消息发送者类型出错\";\r\n        return;\r\n    }\r\n    QQItemInfo* info = createQQItemInfo (rootUin, senderType);\r\n    //获取图片所有者的信息\r\n    if(error==DownloadImage::DownloadError){//如果是下载出错\r\n        qDebug()<<\"QQCommand:图片\"<<name<<\"下载出错\";\r\n        QString image_url = getImageUrlById (imageID);//通过图片id获得储存的图片真实下载地址\r\n        QString save_name = name.mid (0, name.size ()-4);//去除末尾的图片后缀才是要保存的图片名字\r\n        Utility::createUtilityClass ()->//重新去下载图片\r\n                downloadImage (this, SLOT(downImageFinished(bool,QString,QString)), \r\n                               QUrl(image_url), path, save_name);//重新下载图片\r\n        return;\r\n    }\r\n    \r\n    ChatMessageInfo* message_info = info->getChatMessageInfoById (messageID);\r\n    //通过图片所在消息的id获取储存消息信息的对象\r\n    QString content = message_info->contentData ();//获得消息储存的内容\r\n    QString old_img = \"<img src=\\\"qrc:/images/duz.png\\\" imageID=\"+QString::number (imageID)+\">\";//旧的img标签中的内容\r\n    QString new_img;\r\n    if(error==DownloadImage::SaveError||error==DownloadImage::NotSupportFormat){\r\n        new_img = \"<img src=\\\"qrc:/images/dud.png\\\">\";//新img标签内容\r\n    }else if(error==DownloadImage::NoError){//如果没有错误\r\n        new_img = \"<img src=\\\"file:///\"+path+\"/\"+name+\"\\\">\";//新img标签内容\r\n    }\r\n    content.replace (old_img, new_img);//将old_img标签替换为新的内容\r\n    message_info->setContentData (content);//替换消息内容，qml端会自动刷新消息\r\n}\r\n\r\nvoid QQCommand::getImageUrlFinished(QNetworkReply *replys)\r\n{\r\n    ImageInfo image_info = queue_imageInfo.dequeue ();//从列队中取出队首\r\n    if(replys->error() == QNetworkReply::NoError)//如果网络请求没有出错\r\n    {\r\n        QString image_url = replys->rawHeader (\"Location\");//从返回的http头部中取出图片的真实下载地址\r\n        if(image_url==\"\"){//如果真实下载地址为空\r\n            qDebug()<<\"QQCommand:获取图片\"<<image_info.imageID<<\"的真实下载地址失败，网络返回内容为：\"<<replys->readAll ();\r\n            return;\r\n        }\r\n        const QQItemInfo* root_info = image_info.messageInfo->getParent ();\r\n        //获取图片所有者信息的对象（如果图片为好友发送，那就是那个好友的info，如果是群，那就是群的ifno）\r\n        QString save_path = root_info->localCachePath ()+\"/cacheImage\";//获取图片的缓存路径\r\n        QString save_name = root_info->uin ()+\"_\"+\r\n                QString::number (image_info.messageInfo->messageId ())+\"_\"+\r\n                QString::number (image_info.imageID)+\"_\"+\r\n                QDateTime::currentDateTime ().toString (Qt::ISODate).replace (QRegExp(\"\\\\D\"),\"\");//设置要保存的图片名（不加后缀）\r\n        setImageUrlById (image_info.imageID, image_url);//将图片id和真实下载链接的对应关系储存起来\r\n        Utility::createUtilityClass ()->//启动网络请求获取图片\r\n                downloadImage (this, SLOT(downImageFinished(bool,QString,QString)), \r\n                               QUrl(image_url), save_path, save_name);\r\n    }else{//如果获取图片的真实下载地址出错\r\n        queue_imageInfo<<image_info;//不要忘了把图片信息重新加到列队\r\n        http_image->get (this, SLOT(getImageUrlFinished(QNetworkReply*)), image_info.filePath);\r\n        //重新去获取图片的真实下载地址\r\n    }\r\n}\r\n\r\nvoid QQCommand::loadApi()\r\n{\r\n    QString fileName = \":/qml/Api/api.js\";\r\n    QFile scriptFile(fileName);\r\n    if (!scriptFile.open(QIODevice::ReadOnly))\r\n        qDebug()<<\"QQCommand:打开\"+fileName+\"失败\";\r\n    QString contents = scriptFile.readAll ();\r\n    scriptFile.close();\r\n    jsEngine->evaluate(contents, fileName);\r\n}\r\n\r\nQString QQCommand::disposeMessage(QJsonObject &obj, ChatMessageInfo* message_info)\r\n{\r\n    QString result=\"<html><body>\";\r\n    FontStyle font_style;\r\n    QJsonArray content = obj[\"content\"].toArray ();\r\n    QJsonValue temp2 = content[0];\r\n    if(temp2.isArray ()){\r\n        QJsonArray font = temp2.toArray ();\r\n        foreach (QJsonValue temp3, font) {\r\n            if(temp3.isObject ()){\r\n                obj = temp3.toObject ();\r\n                font_style.size = 3;//obj[\"size\"].toInt ();\r\n                font_style.color = \"black\";//obj[\"color\"].toString ();\r\n                //QJsonArray style = obj[\"style\"].toArray ();\r\n                font_style.bold = false;//(bool)style[0].toInt ();//加黑\r\n                font_style.italic = false;//(bool)style[1].toInt ();//斜体\r\n                font_style.underline = false;//(bool)style[2].toInt ();//下划线\r\n                font_style.family = \"新宋体\";//obj[\"name\"].toString ();\r\n            }\r\n        }\r\n    }\r\n    for( int i=1;i<content.size ();++i ){\r\n        temp2 = content[i];\r\n        if(temp2.isArray ()){\r\n            QJsonArray array = temp2.toArray ();\r\n            QString array_name = array[0].toString ();\r\n            if(array_name==\"cface\"){//为群图片消息\r\n                foreach (QJsonValue temp3, array) {\r\n                    if(temp3.isObject ()){\r\n                        obj = temp3.toObject ();\r\n                        QString file_id = doubleToString (obj, \"file_id\");\r\n                        //QString key = obj[\"key\"].toString ();\r\n                        QString name = obj[\"name\"].toString ();\r\n                        name.replace (\"{\", \"%7B\");\r\n                        name.replace (\"}\", \"%7D\");\r\n                        QString server = obj[\"server\"].toString ();\r\n                        QStringList tem_list = server.split (\":\");\r\n                        server = tem_list[0];\r\n                        QString port = tem_list[1];\r\n                        \r\n                        GroupInfo* root_info = qobject_cast<GroupInfo*>(const_cast<QQItemInfo*>(message_info->getParent ()));\r\n                        if(root_info==NULL){\r\n                            qDebug()<<\"QQCommand:将消息对象从QQItemInfo转换为GroupInfo失败\";\r\n                            result.append (textToHtml (font_style, \"[图片加载失败...]\"));\r\n                        }else{\r\n                            QString file_path = \"http://web2.qq.com/cgi-bin/get_group_pic?type=0&gid=\"+\r\n                                    root_info->code ()+\"&uin=\"+message_info->senderUin ()+\r\n                                    \"&rip=\"+server+\"&rport=\"+port+\"&fid=\"+file_id+\r\n                                    \"&pic=\"+name+\"&vfwebqq=\"+property (\"vfwebqq\").toString ();\r\n                            result.append (disposeImageMessage(message_info, file_path));\r\n                        }\r\n                    }\r\n                }\r\n            }else if(array_name==\"offpic\"){//为图片消息\r\n                foreach (QJsonValue temp3, array) {\r\n                    if(temp3.isObject ()){\r\n                        obj = temp3.toObject ();\r\n                        QString file_path = obj[\"file_path\"].toString ();\r\n                        file_path.replace (\"/\", \"%2F\");\r\n                        file_path = \"http://d.web2.qq.com/channel/get_offpic2?file_path=\"+file_path+\"&f_uin=\"+message_info->senderUin ()\r\n                                +\"&clientid=\"+property (\"clientid\").toString ()\r\n                                +\"&psessionid=\"+property (\"psessionid\").toString ();\r\n                        result.append (disposeImageMessage(message_info, file_path));\r\n                        //处理图片消息，并将处理的结果添加到result\r\n                    }\r\n                }\r\n            }else if(array_name==\"face\"){//为表情消息\r\n                QString faceName = QString::number (array[1].toInt ());//转化为int\r\n                QString pngFace_number = \"21 25 32 33 34 36 39 42 45 50 59 64 85 86 91 124\";\r\n                if(pngFace_number.indexOf (faceName)>=0)\r\n                    faceName.append (\".png\");\r\n                else\r\n                    faceName.append (\".gif\");\r\n                QString data = \"<img widht=\\\"25\\\" height=\\\"25\\\" src=\\\"qrc:/faces/classic/\"+faceName+\"\\\">\";\r\n                //qDebug()<<data;\r\n                result.append (data);//添加纯文本消息\r\n                //qDebug()<<\"表情消息,\"<<\"表情代码：\"<<array[1].toInt ();\r\n                //data.append (QString(\"{\")+\"\\\"type\\\":\"+QString::number (Face)+\",\\\"face_code\\\":\"+QString::number (array[1].toInt ())+\"},\");\r\n            }else{\r\n                qDebug()<<\"其他类型的数据：\"<<array_name;\r\n            }\r\n        }else if(temp2.isString ()&&temp2.toString ()!=\"\"){//否则为纯文本消息\r\n            QString textFace_str = \"双喜 鞭炮 灯笼 发财 K歌 购物 邮件 帅 喝彩 祈祷 爆筋 棒棒糖 喝奶 下面 香蕉 飞机 开车 高铁左车头 车厢 高铁右车头 多云 下雨 钞票 熊猫 灯泡 风车 闹钟 打伞 彩球 钻戒 沙发 纸巾 药 手枪 青蛙\";\r\n            QString content = temp2.toString ();\r\n            QRegExp reg(\"\\\\[.+\\\\]\");\r\n            QStringList list = content.split (reg);\r\n            reg.indexIn (content);\r\n\r\n            for (int i=0;i<list.length ();++i) {\r\n                QString str = list[i];\r\n                if(str!=\"\"){\r\n                    str = textToHtml (font_style, str);\r\n                    result.append (str);\r\n                }\r\n                if(i<=reg.captureCount ()){\r\n                    str = reg.cap (i);\r\n                    str.replace (\"[\",\"\");\r\n                    str.replace (\"]\",\"\");\r\n                    if(str==\"\") break;\r\n                    if(str!=\" \"&&textFace_str.indexOf (str)>=0){//如果是表情代码\r\n                        str = \"<img widht=\\\"25\\\" height=\\\"25\\\" src=\\\"qrc:/faces/classic/\"+str+\".png\\\">\";\r\n                    }else{\r\n                        str = textToHtml (font_style, \"[\"+str+\"]\");\r\n                    }\r\n                    result.append (str);\r\n                }\r\n            }\r\n        }\r\n    }\r\n    return result+\"</body></html>\";\r\n}\r\n\r\nvoid QQCommand::disposeFriendStatusChanged(QJsonObject &obj)\r\n{\r\n    QString uin = doubleToString (obj, \"uin\");\r\n    QString status = obj[\"status\"].toString ();\r\n    createFriendInfo (uin)->setStateToString (status);//设置好友状态\r\n}\r\n\r\nvoid QQCommand::disposeFriendMessage(QJsonObject &obj, QQCommand::MessageType type)\r\n{\r\n    //qDebug()<<\"是聊天消息\";\r\n    QString from_uin = doubleToString (obj, \"from_uin\");\r\n    //int msg_id = obj.value (\"msg_id\").toInt ();\r\n    //int msg_id2 = obj.value (\"msg_id2\").toInt ();\r\n    //QString msg_type = doubleToString (obj, \"msg_type\");\r\n    //QString reply_ip = doubleToString (obj, \"reply_ip\");\r\n    //QString to_uin = doubleToString (obj, \"to_uin\");\r\n\r\n    switch (type) \r\n    {\r\n    case GeneralMessage:{\r\n        QQItemInfo *info = createQQItemInfo (from_uin, QQItemInfo::Friend);//先获取消息发送者的信息\r\n        int msg_id = info->getMessageIndex();//为新消息获取一个id\r\n        \r\n        ChatMessageInfo *message_info = info->getChatMessageInfoById (msg_id);\r\n        //通过消息id获得一个储存消息各种信息的对象\r\n        message_info->setSenderUin (from_uin);//将消息的信息存进去\r\n        message_info->setDate (QDate::currentDate ());//将消息发送日期存进去\r\n        message_info->setTime (QTime::currentTime ());//将消息发送时间存进去\r\n        QString data = disposeMessage (obj, message_info);//处理这条消息的内容（一定要放在SenderUin之后）\r\n        message_info->setContentData (data);//将处理后的内容设置给消息对象\r\n        \r\n        info->addChatRecord (message_info);//将消息加到发送者info对象中\r\n        \r\n        //qDebug()<<\"收到了好友消息：\"<<data;\r\n        emit newMessage (from_uin, (int)QQItemInfo::Friend, message_info);//发送信号告诉qml有新的消息\r\n        break;\r\n    }\r\n    case InputNotify:\r\n        emit friendInputNotify (from_uin);//发送好友正在输入的信号\r\n        break;\r\n    case FileMessage:{\r\n        /*QString mode = obj[\"mode\"].toString ();\r\n        if( mode==\"recv\" ){\r\n            QString file_name = obj[\"name\"].toString ();\r\n            emit messageArrive (Friend, from_uin, \"{\\\"content\\\":[{\\\"type\\\":\"+QString::number (FileMessage)+\",\\\"flag\\\":1,\\\"name\\\":\\\"\"+file_name+\"\\\"}]}\");\r\n        }else{\r\n            emit messageArrive (Friend, from_uin, \"{\\\"content\\\":[{\\\"type\\\":\"+QString::number (FileMessage)+\",\\\"flag\\\":0}]}\");\r\n        }*/\r\n        break;\r\n    }\r\n    case AvRequest:\r\n        break;\r\n    case AvRefuse:\r\n        break;\r\n    case ShakeWindow://如果是窗口抖动的消息\r\n        addChatPage (from_uin, QQItemInfo::Friend);//现将此聊天窗口显示出来\r\n        emit shakeWindow (from_uin);//然后发送信号告诉窗口有人抖动他\r\n        break;\r\n    default:\r\n        break;\r\n    }\r\n}\r\n\r\nvoid QQCommand::disposeGroupMessage(QJsonObject &obj, QQCommand::MessageType type)\r\n{\r\n    //qDebug()<<\"是群消息\";\r\n    QString from_uin = doubleToString (obj, \"from_uin\");\r\n    //QString group_code = doubleToString (obj, \"group_code\");\r\n    //int msg_id = obj.value (\"msg_id\").toInt ();\r\n    //int msg_id2 = obj.value (\"msg_id2\").toInt ();\r\n    //QString msg_type = doubleToString (obj, \"msg_type\");\r\n    //QString reply_ip = doubleToString (obj, \"reply_ip\");\r\n    //QString to_uin = doubleToString (obj, \"to_uin\");\r\n    QString send_uin = doubleToString (obj, \"send_uin\");//发送者的uin\r\n\r\n    switch (type) {\r\n    case GeneralMessage:{\r\n        QQItemInfo *info = createQQItemInfo (from_uin, QQItemInfo::Group);//先获取储存群信息的对象\r\n        int msg_id = info->getMessageIndex();//同好友消息\r\n        \r\n        ChatMessageInfo *message_info = info->getChatMessageInfoById (msg_id);\r\n        message_info->setSenderUin (send_uin);//注意！！！此处的发送者uin不是群的uin，而是将消息发到群的成员的uin\r\n        message_info->setDate (QDate::currentDate ());\r\n        message_info->setTime (QTime::currentTime ());\r\n        QString data = disposeMessage (obj, message_info);//先处理消息内容\r\n        message_info->setContentData (data);\r\n        \r\n        info->addChatRecord (message_info);//给from_uin的info对象增加聊天记录\r\n        emit newMessage (from_uin, (int)QQItemInfo::Group, message_info);\r\n        break;\r\n    }\r\n    default:\r\n        break;\r\n    }\r\n    \r\n}\r\n\r\nvoid QQCommand::disposeDiscuMessage(QJsonObject &obj, QQCommand::MessageType type)\r\n{\r\n    //qDebug()<<\"是讨论组消息\";\r\n    //QString from_uin = doubleToString (obj, \"from_uin\");;\r\n    QString did = doubleToString (obj, \"did\");\r\n    //int msg_id = obj.value (\"msg_id\").toInt ();\r\n    //int msg_id2 = obj.value (\"msg_id2\").toInt ();\r\n    //QString msg_type = doubleToString (obj, \"msg_type\");\r\n    //QString reply_ip = doubleToString (obj, \"reply_ip\");\r\n    //QString to_uin = doubleToString (obj, \"to_uin\");\r\n    QString send_uin = doubleToString (obj, \"send_uin\");\r\n    \r\n    switch (type) {\r\n    case GeneralMessage:{\r\n        QQItemInfo *info = createQQItemInfo (did, QQItemInfo::Discu);\r\n        int msg_id = info->getMessageIndex();\r\n        \r\n        ChatMessageInfo *message_info = info->getChatMessageInfoById (msg_id);\r\n        message_info->setSenderUin (send_uin);//注意！！！此处的发送者uin不是群的uin，而是将消息发到讨论组的成员的uin\r\n        message_info->setDate (QDate::currentDate ());\r\n        message_info->setTime (QTime::currentTime ());\r\n        QString data = disposeMessage (obj, message_info);//先处理基本消息\r\n        message_info->setContentData (data);\r\n        \r\n        info->addChatRecord (message_info);//给from_uin的info对象增加聊天记录\r\n        emit newMessage (did, (int)QQItemInfo::Discu, message_info);\r\n        break;\r\n    }\r\n    default:\r\n        break;\r\n    }\r\n}\r\n\r\nvoid QQCommand::disposeStrangerMessage(QJsonObject &, QQCommand::MessageType )\r\n{\r\n    /*QString from_uin = doubleToString (obj, \"from_uin\");\r\n    QString msg_id = doubleToString (obj, \"msg_id\");\r\n    QString msg_id2 = doubleToString (obj, \"msg_id2\");\r\n    QString msg_type = doubleToString (obj, \"msg_type\");\r\n    QString reply_ip = doubleToString (obj, \"reply_ip\");\r\n    QString to_uin = doubleToString (obj, \"to_uin\");*/\r\n    \r\n}\r\n\r\nvoid QQCommand::disposeSystemMessage(QJsonObject &obj)\r\n{\r\n    QString type = obj[\"type\"].toString ();\r\n    if(type == \"verify_required\"){//好友验证信息\r\n        QString account = doubleToString (obj, \"account\");\r\n        QString from_uin = doubleToString (obj, \"from_uin\");\r\n        //emit messageArrive (SystemMessage, from_uin, \"{\\\"type\\\":\"+QString::number (FriendVerify)+\",\\\"account\\\"\\\":\"+account+\"\\\"}\");\r\n    }else if(type == \"group_admin_op\"){//管理员变动信息\r\n        QString from_uin = doubleToString (obj, \"from_uin\");\r\n        QString uin = doubleToString (obj, \"uin\");\r\n        QString uin_flag = doubleToString (obj, \"uin_flag\");\r\n        //emit messageArrive (SystemMessage, from_uin, \"{\\\"type\\\":\"+QString::number (GroupAdmin)+\",\\\"uin\\\":\\\"\"+uin+\"\\\",\\\"flag\\\":\\\"\"+uin_flag+\"\\\"}\");\r\n    }else if(type == \"group_leave\"){//群成员变动信息\r\n        QString from_uin = doubleToString (obj, \"from_uin\");\r\n        QString old_member = doubleToString (obj, \"old_member\");\r\n        //emit messageArrive (SystemMessage, from_uin, \"{\\\"type\\\":\"+QString::number (GroupLeave)+\",\\\"old_member\\\":\\\"\"+old_member+\"\\\"}\");\r\n    }else{//其他系统消息\r\n        qDebug()<<\"其他系统消息:\"<<type;\r\n    }\r\n}\r\n\r\n/*void QQCommand::disposeFileMessage(QJsonObject &obj)\r\n{\r\n    QString from_uin = doubleToString (obj, \"from_uin\");\r\n    QString mode = obj[\"mode\"].toString ();\r\n    if( mode==\"recv\" ){\r\n        QString file_name = obj[\"name\"].toString ();\r\n        emit messageArrive (Friend, from_uin, \"{\\\"content\\\":[{\\\"type\\\":\"+QString::number (SendFile)+\"}, \\\"name\\\":\\\"\"+file_name+\"\\\"]}\");\r\n    }else{\r\n        emit messageArrive (Friend, from_uin, \"{\\\"content\\\":[{\\\"type\\\":\"+QString::number (SendFile)+\"}]}\");\r\n    }\r\n}\r\n\r\nvoid QQCommand::disposeAvMessage(QJsonObject &obj, bool open)\r\n{\r\n    QString from_uin = doubleToString (obj, \"from_uin\");\r\n    emit messageArrive (Friend, from_uin, \"{\\\"content\\\":[{\\\"type\\\":\"+QString::number (open?AvRequest:AvRefuse)+\"}]}\");\r\n}\r\n\r\nvoid QQCommand::disposeShakeMessage(QJsonObject &obj)\r\n{\r\n    QString from_uin = doubleToString (obj, \"from_uin\");\r\n    emit messageArrive (Friend, from_uin, \"{\\\"content\\\":[{\\\"type\\\":\"+QString::number (ShakeWindow)+\"}]}\");\r\n}*/\r\n\r\nQString QQCommand::doubleToString(QJsonObject &obj, const QString &name)\r\n{\r\n    if(!obj.isEmpty ()){\r\n        QJsonValue temp = obj[name];\r\n        if(temp.isDouble ())\r\n            return QString::number ((quint64)obj[name].toDouble ());\r\n    }\r\n    return name;\r\n}\r\n\r\nQString QQCommand::textToHtml(QQCommand::FontStyle &style, QString data)\r\n{\r\n    data.replace(\"&\",\"&amp;\");     \r\n    data.replace(\">\",\"&gt;\");\r\n    data.replace(\"<\",\"&lt;\");\r\n    data.replace(\"\\\"\",\"&quot;\");\r\n    data.replace(\"\\'\",\"&#39;\");\r\n    data.replace(\" \",\"&nbsp;\");\r\n    data.replace(\"\\n\",\"<br>\");\r\n    data.replace(\"\\r\",\"<br>\");\r\n    //上面这几行代码的顺序不能乱，否则会造成多次替换\r\n    \r\n    QString result=\"<font\";\r\n    if(style.size>0)\r\n        result.append (\" size=\\\"\"+QString::number (style.size)+\"\\\"\");\r\n    if(style.color!=\"\"){\r\n        if(style.color[0].isNumber ())\r\n            result.append (\" color=\\\"#\"+style.color+\"\\\"\");\r\n        else\r\n            result.append (\" color=\\\"\"+style.color+\"\\\"\");\r\n    }\r\n    if(style.family!=\"\")\r\n        result.append (\" face=\\\"\"+style.family+\"\\\"\");\r\n    result.append (\">\");\r\n    if(style.bold)\r\n        result.append (\"<b>\");\r\n    if(style.underline)\r\n        result.append (\"<u>\");\r\n    if(style.italic)\r\n        result.append (\"<i>\");\r\n    result.append (data);//把文本包含进去\r\n    if(style.italic)\r\n        result.append (\"</i>\");\r\n    if(style.underline)\r\n        result.append (\"</u>\");\r\n    if(style.bold)\r\n        result.append (\"</b>\");\r\n    result.append (\"</font>\");\r\n    \r\n    return result;\r\n}\r\n\r\nQQItemInfo *QQCommand::createQQItemInfo(const QString& uin, const QString& typeString)\r\n{\r\n    if(uin==\"\"||typeString==\"\"){\r\n        qDebug()<<\"QQCommand-createQQItemInfo:参数不合法,uin:\"<<uin<<\"type:\"+typeString;\r\n        return NULL;\r\n    }\r\n    \r\n    QString name = typeString+uin;\r\n    if(map_itemInfo.value (name, NULL)){\r\n        QQItemInfo* info = qobject_cast<QQItemInfo*>(map_itemInfo[name]);\r\n        return info;\r\n    }\r\n    QQmlEngine *engine = Utility::createUtilityClass ()->qmlEngine ();\r\n    QQmlComponent component(engine, QUrl(\"qrc:/qml/QQItemInfo/\"+typeString+\"Info.qml\"));\r\n    QQItemInfo* info = qobject_cast<QQItemInfo*>(component.create ());\r\n    if(info!=NULL){\r\n        map_itemInfo[name] = info;\r\n        info->setParent (this);\r\n        info->setUserQQ (userQQ());\r\n        info->setUin (uin);\r\n    }\r\n    return info;\r\n}\r\n\r\nvoid QQCommand::setLoginStatus(QQCommand::LoginStatus arg)\r\n{\r\n    if (m_loginStatus != arg) {\r\n        if(arg == WaitLogin&&m_loginStatus==LoginFinished){//如果登录状态变为离线\r\n            poll2_timer->stop ();//停止计算请求是否超时的计时器\r\n            reply->abort ();//停止心跳包\r\n            closeChatWindow();//关闭好友聊天的窗口\r\n            clearQQItemInfos();//清空所有的好友信息\r\n            chatImageID = 0;//chatImageID回到缺省值\r\n            map_imageUrl.clear ();//情况image的id和url值对\r\n            if(!window_mainPanel.isNull ())//销毁主面板窗口\r\n                window_mainPanel->deleteLater ();\r\n            loadLoginWindow();//打开登录窗口\r\n        }else if(arg == LoginFinished){//如果登录完成\r\n            if(!window_login.isNull ())//关闭聊天窗口\r\n                window_login->deleteLater ();\r\n            loadMainPanelWindow ();//加载主面板窗口\r\n        }\r\n        m_loginStatus = arg;\r\n        emit loginStatusChanged();\r\n    }\r\n}\r\n\r\nvoid QQCommand::startPoll2(const QByteArray &data)\r\n{\r\n    poll2_data = data;\r\n    //poll2_timer.start ();\r\n    beginPoll2();\r\n}\r\n\r\nvoid QQCommand::setUserQQ(QString arg)\r\n{\r\n    if (m_userQQ != arg) {\r\n        m_userQQ = arg;\r\n        FriendInfo::setUserQQ (arg);\r\n        FriendInfo::setAccount (arg);\r\n        FriendInfo::setUin (arg);\r\n        emit userQQChanged();\r\n    }\r\n}\r\n\r\nvoid QQCommand::setUserPassword(QString arg)\r\n{\r\n    if (m_userPassword != arg) {\r\n        //qDebug()<<\"设置了密码\"<<arg;\r\n        m_userPassword = arg;\r\n        emit userPasswordChanged();\r\n    }\r\n}\r\n\r\nvoid QQCommand::showWarningInfo(QString message)\r\n{\r\n    QQmlEngine *engine = Utility::createUtilityClass ()->qmlEngine ();\r\n    if(warning_info_window){\r\n        warning_info_window->show ();\r\n    }else{\r\n        QQmlComponent component(engine, QUrl(\"qrc:/qml/Utility/MyMessageBox.qml\"));\r\n        QObject *obj = component.create ();\r\n        warning_info_window = qobject_cast<MyWindow*>(obj);\r\n        if(obj)\r\n            obj->setProperty (\"text\", QVariant(message));\r\n        else\r\n            qDebug()<<\"创建MyMessageBox.qml失败\";\r\n    }\r\n}\r\n\r\nvoid QQCommand::downloadImage(int senderType, QUrl url, QString account, QString imageSize, QJSValue callbackFun)\r\n{\r\n    QString path = QQItemInfo::localCachePath ((QQItemInfo::QQItemType)senderType, userQQ(), account);\r\n    //先获取此qq为account，类型为senderType的缓存目录，将此目录传给下载图片的函数。此图片下载完成就会存入此路径\r\n    Utility::createUtilityClass ()->downloadImage (callbackFun, url, path, \"avatar-\"+imageSize);\r\n}\r\n\r\nvoid QQCommand::showCodeWindow(const QJSValue callbackFun, const QString code_uin)\r\n{\r\n    QQmlEngine *engine = Utility::createUtilityClass ()->qmlEngine ();\r\n    if(!code_window){\r\n        QQmlComponent component(engine, QUrl(\"qrc:/qml/Utility/CodeInput.qml\"));\r\n        QObject *obj = component.create ();\r\n        if(obj){\r\n            code_window = qobject_cast<MyWindow*>(obj);\r\n        }else{\r\n            qDebug()<<\"创建CodeInput.qml失败\";\r\n            return;\r\n        }\r\n    }\r\n    //qDebug()<<\"显示验证码\"<<code_uin<<code_window;\r\n    if(code_window){\r\n        QJSValue value = engine->newQObject (code_window);\r\n        if(value.isObject ())\r\n            value.setProperty (\"backFun\", callbackFun);\r\n        QString url = \"https://ssl.captcha.qq.com/getimage?aid=1003903&r=0.9101365606766194&uin=\"+userQQ()+\"&cap_cd=\"+code_uin;\r\n        code_window->setProperty (\"source\", url);\r\n        code_window->show ();\r\n    }\r\n}\r\n\r\nvoid QQCommand::closeCodeWindow()\r\n{\r\n    if(code_window){\r\n        code_window->close ();\r\n        code_window->deleteLater ();\r\n    }\r\n}\r\n\r\nvoid QQCommand::updataCode()\r\n{\r\n    if(code_window){\r\n        QMetaObject::invokeMethod (code_window, \"updateCode\");//调用刷新验证码\r\n    }\r\n}\r\n\r\nFriendInfo* QQCommand::createFriendInfo(const QString uin)\r\n{\r\n    FriendInfo* info = qobject_cast<FriendInfo*>(createQQItemInfo(uin, QQItemInfo::Friend));\r\n    return info;\r\n}\r\n\r\nGroupInfo* QQCommand::createGroupInfo(const QString uin)\r\n{\r\n    GroupInfo* info = qobject_cast<GroupInfo*>(createQQItemInfo(uin, QQItemInfo::Group));\r\n    return info;\r\n}\r\n\r\nDiscuInfo* QQCommand::createDiscuInfo(const QString uin)\r\n{\r\n    DiscuInfo* info = qobject_cast<DiscuInfo*>(createQQItemInfo(uin, QQItemInfo::Discu));\r\n    return info;\r\n}\r\n\r\nvoid QQCommand::addChatPage(QString uin, int senderType)\r\n{\r\n    if(uin==\"\"||senderType<0)\r\n        return;\r\n    QString typeStr = QQItemInfo::typeToString ((QQItemInfo::QQItemType)senderType);//获取此类型的字符串表达形式\r\n    \r\n    qDebug()<<\"QQCommand:将要增加聊天页面的类型是\"<<senderType<<typeStr;\r\n\r\n    if(map_chatPage.contains(typeStr+uin)){//如果已经存在\r\n        emit activeChatPageChanged (map_chatPage[typeStr+uin]);//活跃的聊天Page改变为temp\r\n        mainChatWindowCommand->show ();//显示出聊天窗口\r\n        return;//如果已经处在此Page就返回\r\n    }\r\n    \r\n    QQmlEngine *engine = Utility::createUtilityClass ()->qmlEngine ();\r\n    if(mainChatWindowCommand.isNull ()){\r\n        QQmlComponent component(engine, QUrl(\"qrc:/qml/Chat/ChatWindowCommand.qml\"));\r\n        QObject *temp_obj = component.create ();\r\n        //qDebug()<<\"创建窗口是否出错：\"<<component.errorString ();\r\n        mainChatWindowCommand = qobject_cast<MyWindow*>(temp_obj);\r\n        if(mainChatWindowCommand){\r\n            connect (mainChatWindowCommand.data (), &MyWindow::closeing, this, &QQCommand::onChatMainWindowClose);\r\n            //链接信号和槽，为聊天主窗口关闭时销毁对象所用\r\n            foreach (QQuickItem *item, mainChatWindowCommand->contentItem ()->childItems ()) {\r\n                if(item->objectName () == \"ChatWindowCommandItem\"){\r\n                    mainChatWindowCommand_item = item;//将聊天页面的父对象储存起来\r\n                    break;\r\n                }\r\n            }\r\n        }else{\r\n            qDebug()<<\"创建ChatWindowCommand.qml出错\";\r\n            return;//如果出错就返回\r\n        }\r\n    }\r\n\r\n    QString qmlName = \"qrc:/qml/Chat/\"+typeStr+\"ChatPage.qml\";\r\n    QQmlComponent component(engine, QUrl(qmlName));\r\n    QQuickItem *item = qobject_cast<QQuickItem*>(component.create ());//新建聊天页面\r\n    if(item&&mainChatWindowCommand_item){\r\n        item->setParentItem (mainChatWindowCommand_item);//设置聊天页面的父对象\r\n        item->setProperty (\"myuin\", uin);//设置他的uin\r\n        item->setProperty (\"type\", senderType);//设置他的类型\r\n        map_chatPage[typeStr+uin] = item;//储存聊天页面\r\n        QQItemInfo* item_info = createQQItemInfo (uin, typeStr);\r\n        if(item_info==NULL){//如果对象为空就返回\r\n            qDebug()<<\"QQCommand-addChatPage:创建QQItemInfo对象失败\";\r\n            return;\r\n        }\r\n        emit addChatPageToWindow (item);//发送信号告知qml增加了聊天页\r\n    }else{\r\n        qDebug()<<\"创建\"+qmlName+\"出错\";\r\n    }\r\n    mainChatWindowCommand->show ();//显示出聊天窗口\r\n}\r\n\r\nvoid QQCommand::removeChatPage(QString uin, int senderType)\r\n{\r\n    QQItemInfo::QQItemType type = (QQItemInfo::QQItemType)senderType;\r\n    QString typeStr = QQItemInfo::typeToString (type);//获取此类型的字符串表达形式\r\n    qDebug()<<\"QQCommand:要关闭的聊天页的类型是：\"<<senderType<<typeStr;\r\n\r\n    QQuickItem *item = map_chatPage.value (typeStr+uin, NULL);\r\n    if(item!=NULL){\r\n        item->deleteLater ();//销毁此对象\r\n    }else{\r\n        qDebug()<<typeStr+uin<<\"page已经为NULL\";\r\n    }\r\n    map_chatPage.remove (typeStr+uin);//移除此对象\r\n    //qDebug()<<item;\r\n    foreach (QQuickItem *temp, map_chatPage) {//改变当前活跃页面为首先找到的第一个不为空的chatPage\r\n        if(temp){\r\n            //qDebug()<<temp;\r\n            emit activeChatPageChanged (temp);\r\n            break;\r\n        }else{\r\n            QString key = map_chatPage.key (temp);\r\n            map_chatPage.remove (key);//如果对象已经为空则移除此对象\r\n            qDebug()<<key+\"为NULL，已被销毁\";\r\n        }\r\n    }\r\n}\r\n\r\nQVariant QQCommand::value(const QString &key, const QVariant &defaultValue) const\r\n{\r\n    return mysettings->value (key, defaultValue);\r\n}\r\n\r\nvoid QQCommand::setValue(const QString &key, const QVariant &value)\r\n{\r\n    mysettings->setValue (key, value);\r\n}\r\n\r\nvoid QQCommand::shakeChatMainWindow(QQuickItem *item)\r\n{\r\n    emit activeChatPageChanged (item);\r\n    if(QMetaObject::invokeMethod (mainChatWindowCommand, \"windowShake\")){\r\n        qDebug()<<\"窗口抖动成功\";\r\n    }else{\r\n        qDebug()<<\"窗口抖动失败\";\r\n    }\r\n}\r\n\r\nvoid QQCommand::openSqlDatabase()\r\n{\r\n    FriendInfo::openSqlDatabase (userQQ());//打开数据库\r\n}\r\n\r\nvoid QQCommand::closeChatWindow()\r\n{\r\n    if(!mainChatWindowCommand.isNull ())\r\n        mainChatWindowCommand->close ();\r\n}\r\n\r\nQString QQCommand::getMovieImageFrameCachePath()\r\n{\r\n    return QDir::homePath ()+\"/.webqq\";\r\n}\r\n\r\n/*void QQCommand::saveAlias(int type, QString uin, QString alias)\r\n{\r\n    QString name = QQItemInfo::typeToString ((QQItemInfo::QQItemType)type)+uin;\r\n    map_alias[name] = alias;\r\n}*/\r\n\r\nvoid QQCommand::updataApi(const QString& content)\r\n{\r\n    qDebug()<<\"更新api.js\"<<content;\r\n}\r\n\r\nQQItemInfo *QQCommand::createQQItemInfo(const QString& uin, QQItemInfo::QQItemType type)\r\n{\r\n    QString typeString = QQItemInfo::typeToString (type);\r\n    return createQQItemInfo (uin, typeString);\r\n}\r\n\r\nvoid QQCommand::clearQQItemInfos()\r\n{\r\n    foreach (QQItemInfo* info, map_itemInfo) {\r\n        if(info!=NULL)\r\n            info->deleteLater ();\r\n    }\r\n    map_itemInfo.clear ();\r\n}\r\n\r\nQString QQCommand::disposeImageMessage(ChatMessageInfo* message_info, QString image_url)\r\n{\r\n    int image_id = getImageIndex();//为这个图片获得一个唯一的id\r\n    ImageInfo image_info;//为图片创建一个储存自己信息的结构体对象\r\n    image_info.filePath=image_url;//储存能获取图片真实下载地址的字符串\r\n    image_info.imageID=image_id;//储存图片的id\r\n    image_info.messageInfo=message_info;//储存图片所在消息的对象的指针\r\n    queue_imageInfo<<image_info;//将图片的信息加入队列\r\n    http_image->get (this, SLOT(getImageUrlFinished(QNetworkReply*)), image_url);\r\n    //进行网络请求,获取图片的真实下载地址\r\n    return \"<img src=\\\"qrc:/images/duz.png\\\" imageID=\"+QString::number (image_id)+\">\";\r\n    //返回此字符串，用于img标签的占位，等图片下载完成会替换此img标签\r\n}\r\n\r\nint QQCommand::getImageIndex()\r\n{\r\n    return chatImageID++;\r\n}\r\n\r\nQString QQCommand::getImageUrlById(int image_id)\r\n{\r\n    return map_imageUrl[image_id];\r\n}\r\n\r\nvoid QQCommand::setImageUrlById(int image_id, const QString &url)\r\n{\r\n    //qDebug()<<\"将id为：\"<<image_id<<\"图片的下载地址设置为：\"<<url;\r\n    map_imageUrl[image_id]=url;\r\n}\r\n\r\nvoid QQCommand::loadLoginWindow()\r\n{\r\n    if(window_login.isNull ()){\r\n        QQmlEngine *engine = Utility::createUtilityClass ()->qmlEngine ();\r\n        QQmlComponent component(engine, QUrl(\"qrc:/qml/Login/main.qml\"));\r\n        QObject *temp_obj = component.create ();\r\n        window_login = qobject_cast<MyWindow*>(temp_obj);\r\n        if(window_login.isNull ()){\r\n            qDebug()<<\"QQCommand:加载登录窗口失败,\"<<component.errorString ();\r\n        }\r\n    }else{\r\n        window_login->show ();\r\n    }\r\n}\r\n\r\nvoid QQCommand::loadMainPanelWindow()\r\n{\r\n    if(window_mainPanel.isNull ()){\r\n        QQmlEngine *engine = Utility::createUtilityClass ()->qmlEngine ();\r\n        QQmlComponent component(engine, QUrl(\"qrc:/qml/MainPanel/main.qml\"));\r\n        QObject *temp_obj = component.create ();\r\n        window_login = qobject_cast<MyWindow*>(temp_obj);\r\n        if(window_login.isNull ()){\r\n            qDebug()<<\"QQCommand:加载主面板窗口失败,\"<<component.errorString ();\r\n        }\r\n    }else{\r\n        window_mainPanel->show ();\r\n    }\r\n}\r\n\r\nbool QQCommand::isChatPageExist(const QString& uin, int senderType)\r\n{\r\n    QString typeStr = QQItemInfo::typeToString ((QQItemInfo::QQItemType)senderType);//获取此类型的字符串表达形式\r\n    return map_chatPage.contains(typeStr+uin);\r\n}\r\n\r\nvoid QQCommand::addFriendUin(const QString &uin)\r\n{\r\n    friendsUin.append (uin+\" \");\r\n    //qDebug()<<\"增加好友uin:\"+uin<<friendsUin;\r\n}\r\n\r\nbool QQCommand::isStranger(const QString &uin)\r\n{\r\n    return friendsUin.indexOf (uin)<0;\r\n}\r\n\r\nQString QQCommand::getHash()\r\n{\r\n    QJSValueList list;\r\n    list<<QJSValue(userQQ())<<QJSValue(Utility::createUtilityClass ()->getCookie (\"ptwebqq\"));\r\n    return jsEngine->globalObject ().property (\"getHash\").call (list).toString ();\r\n}\r\n\r\nQString QQCommand::encryptionPassword(const QString &uin, const QString &code)\r\n{\r\n    QJSValueList list;\r\n    list<<QJSValue(userPassword())<<QJSValue(uin)<<QJSValue(code);\r\n    return jsEngine->globalObject ().property (\"encryptionPassword\").call (list).toString ();\r\n}\r\n\r\nQVariant QQCommand::getLoginedQQInfo()\r\n{\r\n    Utility *utility = Utility::createUtilityClass ();\r\n    QByteArray reply=\"[\";\r\n    QString qqs = utility->value (\"qq_account\", \"\").toString ();\r\n    QStringList qq_list = qqs.split (\",\");\r\n    foreach (QString qq, qq_list) {\r\n        if(qq!=\"\"){\r\n            QStringList temp = qq.split (\".\");\r\n            if(temp.size ()==2){//如果有两个，一个为qq号，一个为昵称\r\n                FriendInfo info;\r\n                QString account = temp[0];\r\n                info.setUserQQ (account);\r\n                info.setAccount (account);\r\n                reply.append (\"{\\\"account\\\":\\\"\"+account\r\n                              +\"\\\",\\\"nick\\\":\\\"\"+QByteArray::fromHex (temp[1].toUtf8 ())\r\n                        +\"\\\",\\\"avatarSource\\\":\\\"\"+info.avatar240 ()+\"\\\"},\");\r\n            }\r\n        }\r\n    }\r\n    reply.replace (reply.size ()-1,1,\"]\");\r\n    return QVariant(QJsonDocument::fromJson (reply).array ());\r\n}\r\n\r\nvoid QQCommand::removeLoginedQQInfo(const QString account, bool rmLocalCache)\r\n{\r\n    Utility *utility = Utility::createUtilityClass ();\r\n    QString qqs = utility->value (\"qq_account\", \"\").toString ();\r\n    QStringList qq_list = qqs.split (\",\");\r\n    foreach (QString qq, qq_list) {\r\n        if(qq!=\"\"){\r\n            QStringList temp = qq.split (\".\");\r\n            if(temp.size ()==2){//如果有两个，一个为qq号，一个为昵称\r\n                if(temp[0]==account){//如果查找到此qq\r\n                    qqs.replace (qq+\",\", \"\");//替换掉\r\n                    utility->setValue (\"qq_account\", qqs);//替换掉原来的值\r\n                    FriendInfo info;\r\n                    info.setUserQQ (account);\r\n                    info.setAccount (account);\r\n                    info.clearSettings ();//清除配置内容\r\n                    if(rmLocalCache){//如果要删除本地缓存\r\n                        utility->removePath (info.localCachePath ());\r\n                    }\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nvoid QQCommand::addLoginedQQInfo(const QString account, const QString nick)\r\n{\r\n    Utility *utility = Utility::createUtilityClass ();\r\n    QString qqs = utility->value (\"qq_account\", \"\").toString ();\r\n    QString addStr = account+\".\"+nick.toUtf8 ().toHex ()+\",\";\r\n    if(qqs.indexOf (addStr)<0){//如果这条信息不存在\r\n        qqs.insert (0, addStr);\r\n        utility->setValue (\"qq_account\", qqs);//添加进去\r\n    }\r\n}\r\n\r\nvoid QQCommand::setWindowScale(double arg)\r\n{\r\n    if (m_windowScale != arg) {\r\n        m_windowScale = arg;\r\n        emit windowScaleChanged();\r\n    }\r\n}\r\n\r\nint QQCommand::openMessageBox(QJSValue value)\r\n{\r\n    MyMessageBox message;\r\n    message.setStyleSource (QUrl::fromLocalFile (\"style/messageBoxStyle.css\"));\r\n    QJSValue temp = value.property (\"icon\");\r\n    if( !temp.isUndefined () ){\r\n        message.setIcon ((MyMessageBox::Icon)temp.toInt ());\r\n    }\r\n    temp = value.property (\"detailedText\");\r\n    if( !temp.isUndefined () ) {\r\n        message.setDetailedText (temp.toString ());\r\n    }\r\n    temp = value.property (\"standardButtons\");\r\n    if( !temp.isUndefined () ) {\r\n        message.setStandardButtons ((MyMessageBox::StandardButtons)temp.toInt ());\r\n    }\r\n    temp = value.property (\"text\");\r\n    if( !temp.isUndefined () ) {\r\n        message.setText (temp.toString ());\r\n    }\r\n    temp = value.property (\"iconPixmap\");\r\n    if( !temp.isUndefined () ) {\r\n        message.setIconPixmap (QPixmap(temp.toString ()));\r\n    }\r\n    temp = value.property (\"textFormat\");\r\n    if( !temp.isUndefined () ) {\r\n        message.setTextFormat ((Qt::TextFormat)temp.toInt ());\r\n    }\r\n    temp = value.property (\"informativeText\");\r\n    if( !temp.isUndefined () ) {\r\n        message.setInformativeText (temp.toString ());\r\n    }\r\n    temp = value.property (\"textInteractionFlags\");\r\n    if( !temp.isUndefined () ) {\r\n        message.setTextInteractionFlags ((Qt::TextInteractionFlags)temp.toInt ());\r\n    }\r\n    return message.exec ();\r\n}\r\n\r\nvoid QQCommand::setRememberPassword(bool arg)\r\n{\r\n    if (mysettings&&rememberPassword ()!= arg) {\r\n        mysettings->setValue (\"rememberPassword\", arg);\r\n        if(!arg)\r\n            mysettings->remove (\"password\");\r\n        emit rememberPasswordChanged();\r\n    }\r\n}\r\n\r\nvoid QQCommand::setAutoLogin(bool arg)\r\n{\r\n    if (mysettings&&autoLogin() != arg) {\r\n        mysettings->setValue (\"autoLogin\", arg);\r\n        emit autoLoginChanged();\r\n    }\r\n}\r\n\r\nvoid QQCommand::saveUserPassword()\r\n{\r\n    if(rememberPassword()&&mysettings){//先判断是否记住了密码\r\n        QString pass = Utility::createUtilityClass ()->stringEncrypt (userPassword (), \"xingchenQQ\");\r\n        mysettings->setValue (\"password\", pass);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/qqstars/qqstars.h",
    "content": "#ifndef QQCommand_H\r\n#define QQCommand_H\r\n\r\n#include <QObject>\r\n#include <QDebug>\r\n#include <QByteArray>\r\n#include <QTimer>\r\n#include <QQuickItem>\r\n#include <QJSEngine>\r\n#include \"qqiteminfo.h\"\r\n#include \"downloadimage.h\"\r\n\r\nclass MyWindow;\r\nclass MyHttpRequest;\r\nclass NetworkAccessManager;\r\nclass QNetworkRequest;\r\nclass QNetworkReply;\r\nclass QQCommand : public FriendInfo\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QString userQQ READ userQQ WRITE setUserQQ NOTIFY userQQChanged)\r\n    Q_PROPERTY(QString userPassword READ userPassword WRITE setUserPassword NOTIFY userPasswordChanged)\r\n    Q_PROPERTY(LoginStatus loginStatus READ loginStatus WRITE setLoginStatus NOTIFY loginStatusChanged)\r\n    Q_PROPERTY(double windowScale READ windowScale WRITE setWindowScale NOTIFY windowScaleChanged)\r\n    Q_PROPERTY(bool rememberPassword READ rememberPassword WRITE setRememberPassword NOTIFY rememberPasswordChanged)//是否记住密码\r\n    Q_PROPERTY(bool autoLogin READ autoLogin WRITE setAutoLogin NOTIFY autoLoginChanged)//是否自动登录\r\n    Q_PROPERTY(QString codeText READ codeText CONSTANT)\r\n    \r\n    Q_ENUMS(States)\r\n    Q_ENUMS(LoginStatus)\r\n    Q_ENUMS(SenderType)\r\n    Q_ENUMS(MessageType)\r\nprivate:\r\n    static QQCommand *firstQQCommand;\r\npublic:\r\n    static QQCommand *getFirstQQCommand();//返回第一个被创建的QQCommand对象\r\n    explicit QQCommand( QObject *parent = 0);\r\n    enum LoginStatus{//登录状态\r\n        WaitLogin,//离线\r\n        Logining,//登录中\r\n        LoginFinished//登录完成\r\n    };\r\n\r\n    enum SenderType{//发送消息的人的类型\r\n        Friend,//好友\r\n        Group,//群\r\n        Discu,//讨论组\r\n        Stranger,//陌生人\r\n        SystemMessage//系统消息，包含群管理员的更改，成员的更改，还有好友验证消息\r\n    };\r\n    \r\n    enum MessageType{//消息的类型\r\n        InputNotify,//正在输入\r\n        Text,//文本\r\n        Image,//图片\r\n        Face,//表情\r\n        GeneralMessage,//普通消息，包含Text Image Face等\r\n        //SendFile,//发送文件\r\n        //CancleSendFile,//取消发送文件\r\n        FileMessage,//文件消息，包含发送文件和取消发送文件\r\n        AvRequest,//请求开视频\r\n        AvRefuse,//取消开视频\r\n        ShakeWindow,//窗口抖动\r\n        FriendStatusChanged,//好友状态改变\r\n        FriendVerify,//好友验证消息poll_type=system_message，type=verify_required\r\n        GroupAdmin,//群管理员消息poll_type=sys_g_msg，type=group_admin_op，uin_flag=1为设为管理员，0为取消管理员\r\n        GroupLeave//群T人的消息\r\n    };\r\n    \r\n    LoginStatus loginStatus() const;\r\n    QString userQQ() const;\r\n    QString userPassword() const;\r\n    double windowScale() const;\r\n    bool rememberPassword() const;\r\n    bool autoLogin() const;\r\n    QString codeText() const;\r\n    \r\nprivate slots:\r\n    void beginPoll2();//启动心跳包\r\n    void poll2Finished(QNetworkReply *replys);//qq心跳包获取完成时调用\r\n    void initUserPassword();//初始化用户密码(从QSettings中)\r\n    void onChatMainWindowClose();//接收主聊天窗口关闭的信号\r\n    void onSettingsChanged();//处理settings对象改变的信号\r\n    void onStateChanged();//当状态改变后调用，将状态存到本地\r\n    void onPoll2Timeout();//如果心跳包超时\r\n    void onNetworkOnlineStateChanged(bool isOnline);//如果网络在线状态改变\r\n    void downImageFinished(DownloadImage::ErrorType error, const QString& path, const QString& name);\r\n    //下载图片完成时调用，下载的图片是好友发送过来的\r\n    void getImageUrlFinished(QNetworkReply *replys);//获取图片真实的下载地址完成\r\nprivate:\r\n    struct FontStyle{\r\n        int size;//字体大小\r\n        QString color;//字体颜色\r\n        bool bold;//加黑\r\n        bool italic;//斜体\r\n        bool underline;//下划线\r\n        QString family;//字体\r\n    };\r\n    struct ImageInfo{\r\n        int imageID;//图片的编号\r\n        ChatMessageInfo* messageInfo;//所属消息的信息\r\n        QString filePath;//能获取图片真实下载地址的url地址\r\n    };\r\n    \r\n    QPointer<MyWindow> window_login, window_mainPanel;//记录登录窗口的指针\r\n    LoginStatus m_loginStatus;//储存当前用户的登录状态\r\n    QByteArray poll2_data;//post心跳包的数据\r\n    NetworkAccessManager *manager;//储存管理心跳包网络请求的对象\r\n    QNetworkRequest *request;//储存发送心跳包的网络请求对象\r\n    QNetworkReply *reply;//储存进行网络请求的应答对象\r\n    QString m_userQQ;//储存当前用户qq号码\r\n    QString m_userPassword;//储存当前用户密码\r\n    QPointer<MyWindow> code_window;//储存指向输入验证码窗口的指针\r\n    QJSEngine *jsEngine;//储存加载了api(*.js文件)的js引擎\r\n    double m_windowScale;//储存可视控件的比例\r\n    QString m_codeText;//储存输入验证码\r\n    QPointer<MyWindow> warning_info_window;//储存指向警告窗口的指针\r\n    QMap<QString, QQItemInfo*> map_itemInfo;//储存每个好友或群讨论组的Info\r\n    QPointer<MyWindow> mainChatWindowCommand;//储存所有聊天窗口的主管理窗口\r\n    QPointer<QQuickItem> mainChatWindowCommand_item;//储存每一个聊天页面的父对象(聊天窗口anchors.fill此父对象)\r\n    QMap<QString, QQuickItem*> map_chatPage;//储存备已经打开的聊天页面\r\n    QString friendsUin;//用来储存所有好友的uin，陌生人不存在这里，为判断一个uin是否为陌生人做支持\r\n    QTimer* poll2_timer;//心跳包的计时器，如果超时就中断当前心跳包，然后重新重新心跳\r\n    QTimer* abortPoll_timer;//中断心跳包的定时器（为中断心跳包提供一个延时）\r\n    int poll2Timerout_count;//记录网络请求的连续超时次数\r\n    int poll2Error_count;//记录网络请求连续出错的次数\r\n    \r\n    MyHttpRequest* http_image;//下载图片专用的网络请求对象\r\n    int chatImageID;//聊天过程中收到的图片的id编号\r\n    QMap<int, QString> map_imageUrl;//图片的id和真实下载地址之间的映射\r\n    QQueue<ImageInfo> queue_imageInfo;\r\n    \r\n\r\n    void loadApi();\r\n    QString disposeMessage(QJsonObject &obj , ChatMessageInfo *message_info);//解析基本消息\r\n    //void disposeInputNotify( QJsonObject &obj );//处理好友正在输入消息\r\n    void disposeFriendStatusChanged( QJsonObject &obj );//处理好友状态改变\r\n    void disposeFriendMessage( QJsonObject &obj, MessageType type=GeneralMessage );//处理好友消息\r\n    void disposeGroupMessage( QJsonObject &obj, MessageType type=GeneralMessage );//处理群消息\r\n    void disposeDiscuMessage( QJsonObject &obj, MessageType type=GeneralMessage );//处理讨论组消息\r\n    void disposeStrangerMessage( QJsonObject &obj, MessageType type=GeneralMessage );//处理陌生人消息\r\n    void disposeSystemMessage(QJsonObject &obj);//处理系统消息\r\n    //void disposeFileMessage( QJsonObject &obj );//处理文件传输方面的消息\r\n    //void disposeAvMessage( QJsonObject &obj, bool open/*true为开视频，false为取消开视频*/ );//处理视频聊天方面的消息\r\n    //void disposeShakeMessage( QJsonObject &obj );\r\n    QString doubleToString( QJsonObject &obj, const QString& name );//将obj中类型为double的数据转化为QString类型\r\n    QString textToHtml(FontStyle &style, QString data);//将文本内容转化为富文本\r\n    \r\n    QQItemInfo* createQQItemInfo(const QString& uin ,const QString& typeString);\r\n    QQItemInfo* createQQItemInfo(const QString& uin, QQItemInfo::QQItemType type);\r\n    \r\n    void clearQQItemInfos();//清空保存的所有的好友信息\r\n    QString disposeImageMessage(ChatMessageInfo* message_info, QString file_path);\r\n    //获取qq中好友发过来的图片的真实url（需要先get一下某个url，然后返回的数据中有真实的url地址）\r\n    int getImageIndex();//返回一个本次在线中的一个唯一的数字，用于给接收到的图片编码\r\n    QString getImageUrlById(int image_id);\r\n    void setImageUrlById(int image_id, const QString &url);\r\nsignals:\r\n    void loginStatusChanged();\r\n    void poll2ReData( QString data );\r\n    void userQQChanged();\r\n    void error( QString message );//有错误产生就发送信号\r\n    void userPasswordChanged();\r\n    \r\n    void windowScaleChanged();//窗口比例改变\r\n    void rememberPasswordChanged();\r\n    void autoLoginChanged();\r\n\r\n    void friendInputNotify(QString fromUin);//好友正在输入的信号\r\n    void newMessage(QString fromUin, int type, ChatMessageInfo* info);//新的聊天消息信号,qml中的聊天页面会接收此消息\r\n    void shakeWindow(QString fromUin);//窗口抖动信号\r\n    void addChatPageToWindow(QQuickItem* item);//增加聊天页面的信号,此信号被聊天页面所在的window接收\r\n    void activeChatPageChanged(QQuickItem* item);//将item这个page变为活跃的page\r\n    void addRecentContacts(QQItemInfo* info);//发送信号告诉qml的最近联系人列表添加item\r\npublic slots:\r\n    void loadLoginWindow();//加载登录窗口\r\n    void loadMainPanelWindow();//加载qq主面板窗口\r\n    \r\n    void setRememberPassword(bool arg);\r\n    void setAutoLogin(bool arg);\r\n    void saveUserPassword();\r\n    void setLoginStatus(LoginStatus arg);\r\n    void startPoll2( const QByteArray& data );\r\n    void setUserQQ(QString arg);\r\n    void setUserPassword(QString arg);\r\n    void setWindowScale(double arg);\r\n    \r\n    QString getHash();//获取请求好友列表需要的hsah\r\n    QString encryptionPassword(const QString &uin, const QString &code);//加密密码，用来登录\r\n    QVariant getLoginedQQInfo();//获取所有在此电脑上登录过的qq的信息\r\n    void removeLoginedQQInfo(const QString account, bool rmLocalCache=false);//移除qq号码为account的账号信息\r\n    void addLoginedQQInfo(const QString account, const QString nick);//增加一个登录过的qq的记录\r\n    \r\n    int openMessageBox( QJSValue value );//打开一个对话窗口\r\n    void showWarningInfo(QString message);//显示一个警告窗口\r\n    void downloadImage( int senderType/*QQItemType类型*/, QUrl url, QString account, QString imageSize, QJSValue callbackFun );//下载图片\r\n    void showCodeWindow(const QJSValue callbackFun, const QString code_uin);//显示出输入验证码的窗口\r\n    void closeCodeWindow();//关闭输入验证码的窗口\r\n    void updataCode();//刷新验证码的显示\r\n    void updataApi(const QString& content);//重新载入api.js，用于更新api后的操作\r\n    \r\n    FriendInfo* createFriendInfo(const QString uin);//创建一个储存好友信息的对象\r\n    GroupInfo* createGroupInfo(const QString uin);//创建一个储存群信息的对象\r\n    DiscuInfo* createDiscuInfo(const QString uin);//创建一个储存讨论组信息的对象\r\n    \r\n    void addChatPage(QString uin, int senderType/*QQItemType类型*/);//新增聊天窗口\r\n    void removeChatPage(QString uin, int senderType/*QQItemType类型*/);//移除已有的聊天Page\r\n    bool isChatPageExist(const QString& uin, int senderType/*QQItemType类型*/);//判断聊天页面是否存在\r\n    \r\n    void addFriendUin(const QString& uin);//将此uin添加到好友uin列表\r\n    bool isStranger(const QString& uin);//判断此uin是否为陌生人\r\n    \r\n    QVariant value(const QString & key, const QVariant & defaultValue = QVariant()) const;//返回储存在QSettings里边的value;\r\n    void setValue(const QString & key, const QVariant & value);\r\n    void shakeChatMainWindow (QQuickItem *item);//抖动聊天窗口\r\n    void openSqlDatabase();//打开数据库（储存聊天记录等消息）\r\n    \r\n    void closeChatWindow();//关闭聊天窗口\r\n    QString getMovieImageFrameCachePath();//返回给qml显示gif图时每一帧的缓存路径\r\n};\r\n#endif // QQCommand_H\r\n"
  },
  {
    "path": "src/qxtglobalshortcut/myshortcut.cpp",
    "content": "#include \"myshortcut.h\"\r\n#include <QEvent>\r\n#include <QKeyEvent>\r\n#include <QCoreApplication>\r\n#include <QDebug>\r\n#include <QAbstractEventDispatcher>\r\n\r\nMyShortcut::MyShortcut(MyShortcut::Type type, QObject *parent):\r\n    QObject(parent)\r\n{\r\n    m_shortcut = \"\";\r\n    m_enabled = true;\r\n    m_filterOut = true;\r\n    m_shortcutType = type;\r\n}\r\n\r\nMyShortcut::MyShortcut(QString shortcut, MyShortcut::Type type, QObject *parent):\r\n    QObject(parent)\r\n{\r\n    m_shortcut = shortcut;\r\n    m_enabled = true;\r\n    m_filterOut = true;\r\n    m_shortcutType = type;\r\n}\r\n\r\nQString MyShortcut::shortcut() const\r\n{\r\n    return m_shortcut;\r\n}\r\n\r\nbool MyShortcut::isEnabled() const\r\n{\r\n    return m_enabled;\r\n}\r\n\r\nbool MyShortcut::filterOut() const\r\n{\r\n    return m_filterOut;\r\n}\r\n\r\nQObject *MyShortcut::target() const\r\n{\r\n    return m_target;\r\n}\r\n\r\nMyShortcut::Type MyShortcut::shortcutType() const\r\n{\r\n    return m_shortcutType;\r\n}\r\n\r\nvoid MyShortcut::setShortcut(QString arg)\r\n{\r\n    if (m_shortcut != arg) {\r\n        m_shortcut = arg;\r\n        if(shortcutType () == SystemGlobalShortcut){//如果是系统全局热键\r\n            updataSystemGlobalShortcut (arg);//更新系统全局热键\r\n        }\r\n        \r\n        key_list.clear ();\r\n        QStringList list = arg.split (\"+\");\r\n        foreach (QString key, list) {\r\n            if(key!=\"\"){\r\n                if(QString::compare (key, \"Ctrl\", Qt::CaseInsensitive)==0){\r\n                    key_list.append (Qt::Key_Control);\r\n                }else if(QString::compare (key, \"Shift\", Qt::CaseInsensitive)==0){\r\n                    key_list.append (Qt::Key_Shift);\r\n                }else if(QString::compare (key, \"Alt\", Qt::CaseInsensitive)==0){\r\n                    key_list.append (Qt::Key_Alt);\r\n                }else if(QString::compare (key, \"Meta\", Qt::CaseInsensitive)==0){\r\n                    key_list.append (Qt::Key_Meta);\r\n                }else{\r\n                    QKeySequence sequence=QKeySequence::fromString (key);\r\n                    if(sequence!=Qt::Key_unknown){\r\n                        key_list.append (sequence[0]);\r\n                    }else{\r\n                        emit error (\"存在未知按键\");\r\n                        break;\r\n                    }\r\n                }\r\n            }else{\r\n                emit error (\"不可有空按键\");\r\n                break;\r\n            }\r\n            //qDebug()<<key<<key_list.last ();\r\n        }\r\n        emit shortcutChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyShortcut::setEnabled(bool arg)\r\n{\r\n    if (m_enabled != arg) {\r\n        m_enabled = arg;\r\n        if(obj){//如果对象不为空\r\n            if(arg)\r\n                obj->installEventFilter (this);//安装过滤器\r\n            else\r\n                obj->removeEventFilter (this);//移除过滤器\r\n        }\r\n        if(shortcutType ()==SystemGlobalShortcut){//如果是全局的\r\n            if(global_shortcut)\r\n                global_shortcut->setEnabled (arg);\r\n        }\r\n        emit enabledChanged(arg);\r\n    }\r\n}\r\n\r\nbool MyShortcut::onKeyPressed(QQueue<int> &list)\r\n{\r\n    if(list==key_list){//判断是否触发了热键\r\n        emit trigger ();\r\n        return true;\r\n    }\r\n    return false;\r\n}\r\n\r\nvoid MyShortcut::setFilterOut(bool arg)\r\n{\r\n    if (m_filterOut != arg) {\r\n        m_filterOut = arg;\r\n        emit filterOutChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyShortcut::setTarget(QObject *arg)\r\n{\r\n    if (m_target != arg) {\r\n        m_target = arg;\r\n        if(shortcutType ()==LocalShortcut)//如果是局部热键才能设置obj\r\n            setObj (arg);\r\n        emit targetChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyShortcut::setShortcutType(MyShortcut::Type arg)\r\n{\r\n    if (m_shortcutType != arg) {\r\n        m_shortcutType = arg;\r\n        if(arg == AppGlobalShortcut){//如果是程序内部的全局热键\r\n            //qDebug()<<\"设置程序内部全局热键：\"<<QCoreApplication::instance ();\r\n            setObj (QCoreApplication::instance ());//设置过滤对象\r\n            //setObj (QAbstractEventDispatcher::instance ());//设置过滤对象\r\n        }else if(arg == LocalShortcut){\r\n            setObj (target ());//设置过滤对象\r\n        }else if(arg == SystemGlobalShortcut){\r\n            if(obj)\r\n                obj->removeEventFilter (this);//移除过滤器\r\n            if(global_shortcut.isNull ()){\r\n                global_shortcut = new QxtGlobalShortcut(this);\r\n                connect(global_shortcut, SIGNAL(activated()), SIGNAL(trigger()));//连接信号和槽\r\n            }\r\n            updataSystemGlobalShortcut(shortcut ());\r\n        }\r\n        emit shortcutTypeChanged(arg);\r\n    }\r\n}\r\n\r\nvoid MyShortcut::setObj(QObject *arg)\r\n{\r\n    if(obj!=arg){\r\n        if(isEnabled()&&arg){\r\n            arg->installEventFilter (this);//为他安装事件过滤器\r\n            //qDebug()<<\"安装了过滤器\";\r\n        }\r\n        if(obj)\r\n            obj->removeEventFilter (this);//移除原来的过滤器\r\n        obj = arg;//设置为新的过滤对象\r\n    }\r\n}\r\n\r\nvoid MyShortcut::updataSystemGlobalShortcut(const QString &arg)\r\n{\r\n    if(arg==\"\")//不可为空\r\n        return;\r\n    QKeySequence temp = QKeySequence(arg);\r\n    if(global_shortcut&&global_shortcut->shortcut ()!=temp){\r\n        if(!global_shortcut->setShortcut (temp)){\r\n            qDebug()<<\"MyShortcut\"<<\"设置系统全局热键：\"+arg+\"出错\";\r\n            emit error (\"设置系统全局热键：\"+arg+\"出错\");\r\n        }\r\n    }\r\n}\r\n\r\nbool MyShortcut::eventFilter(QObject *watched, QEvent *event)\r\n{\r\n    if(watched == obj||shortcutType () == AppGlobalShortcut){//判断一下是不是obj的事件，或者是全局热键事件\r\n        if(event->type () == QEvent::KeyPress){\r\n            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);\r\n            int key = keyEvent->key ();\r\n            if(queue_key.count ()==0||key!=queue_key.last ())//如果按键不是重复的\r\n                queue_key.append (key);\r\n            else\r\n                return false;\r\n            //qDebug()<<keyEvent->key ();\r\n            return (onKeyPressed (queue_key)&&m_filterOut);\r\n            //如果符合自己的热键设定，就再判断是否过滤掉此次按键事件，是的话才返回true，否则就算符合了热键的设定也将此事件放行给target响应\r\n        }else if(event->type () == QEvent::KeyRelease){\r\n            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);\r\n            queue_key.removeOne (keyEvent->key());\r\n            return false;\r\n        }\r\n        return false;\r\n    }else{//如果是其他obj的时间就返回给parent中的eventFilter处理\r\n        return QObject::eventFilter (watched, event);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/qxtglobalshortcut/myshortcut.h",
    "content": "#ifndef MYSHORTCUT_H\r\n#define MYSHORTCUT_H\r\n/*!\r\n * 使用须知：\r\n * 此类为 雨后星辰后来添加，封装了app内部全局热键（通过给QApplication安装事件过滤器）\r\n * 封装了指定对象热键（为此对象安装事件过滤器实现）\r\n * 最后封装了qxtglobalshortcut实现了系统全局热键，在这里感谢原作者的贡献\r\n * 另外，由于qxtglobalshortcut不支持qt5，所以我额外给他增加了一下代码\r\n * 总结，此类支持对象内热键（必须为QObject类型或继承QObject），程序全局热键，系统全局热键，支持qt5和qt4(未尝试，可以需要修改部分代码)\r\n * 请不要删除这段话，谢谢！ \r\n*/\r\n#include <QObject>\r\n#include <QPointer>\r\n#include <QQueue>\r\n#include \"qxtglobalshortcut.h\"//系统全局热键\r\n\r\nclass MyShortcut : public QObject\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY(QString shortcut READ shortcut WRITE setShortcut NOTIFY shortcutChanged)\r\n    Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)\r\n    Q_PROPERTY(bool filterOut READ filterOut WRITE setFilterOut NOTIFY filterOutChanged)\r\n    //是将事件传递给过滤的对象,对于系统全局热键不可用\r\n    Q_PROPERTY(QObject* target READ target WRITE setTarget NOTIFY targetChanged)\r\n    Q_PROPERTY(Type shortcutType READ shortcutType WRITE setShortcutType NOTIFY shortcutTypeChanged)\r\n    Q_ENUMS(Type)\r\npublic:\r\n    enum Type{\r\n        LocalShortcut,//局部热键\r\n        AppGlobalShortcut,//整个程序的热键\r\n        SystemGlobalShortcut//系统全局热键\r\n    };\r\n    explicit MyShortcut(Type type = LocalShortcut, QObject *parent = 0);\r\n    explicit MyShortcut(QString shortcut, Type type = LocalShortcut, QObject *parent = 0);\r\n    QString shortcut() const;\r\n    bool isEnabled() const;\r\n    bool filterOut() const;\r\n    QObject* target() const;\r\n    \r\n    Type shortcutType() const;\r\npublic slots:\r\n    void setShortcut(QString arg);\r\n    void setEnabled(bool arg);\r\n    void setFilterOut(bool arg);\r\n    void setTarget(QObject* arg);\r\n    void setShortcutType(Type arg);\r\n    \r\nsignals:\r\n    void shortcutChanged(QString arg);\r\n    void trigger();\r\n    void enabledChanged(bool arg);\r\n    void error(QString arg);\r\n    void filterOutChanged(bool arg);\r\n    void targetChanged(QObject* arg);\r\n    void shortcutTypeChanged(Type arg);\r\n    \r\nprivate:\r\n     QString m_shortcut;\r\n     QQueue<int> key_list;\r\n     QQueue<int> queue_key;\r\n     bool m_enabled;\r\n     bool m_filterOut;\r\n     QPointer<QObject> m_target;\r\n     QPointer<QObject> obj;\r\n     QPointer<QxtGlobalShortcut> global_shortcut;\r\n     Type m_shortcutType;\r\n     \r\n     void setObj(QObject *arg);\r\n     void updataSystemGlobalShortcut(const QString &arg);//更新系统全局热键\r\n     bool eventFilter ( QObject * watched, QEvent * event );\r\n     bool onKeyPressed(QQueue<int>& list);\r\n     \r\n};\r\n\r\n#endif // MYSHORTCUT_H\r\n"
  },
  {
    "path": "src/qxtglobalshortcut/qxtglobal.h",
    "content": "/****************************************************************************\n **\n ** Copyright (C) Qxt Foundation. Some rights reserved.\n **\n ** This file is part of the QxtCore module of the Qxt library.\n **\n ** This library is free software; you can redistribute it and/or modify it\n ** under the terms of the Common Public License, version 1.0, as published\n ** by IBM, and/or under the terms of the GNU Lesser General Public License,\n ** version 2.1, as published by the Free Software Foundation.\n **\n ** This file is provided \"AS IS\", without WARRANTIES OR CONDITIONS OF ANY\n ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY\n ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR\n ** FITNESS FOR A PARTICULAR PURPOSE.\n **\n ** You should have received a copy of the CPL and the LGPL along with this\n ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files\n ** included with the source distribution for more information.\n ** If you did not receive a copy of the licenses, contact the Qxt Foundation.\n **\n ** <http://libqxt.org>  <foundation@libqxt.org>\n **\n ****************************************************************************/\n\n#ifndef QXTGLOBAL_H\n#define QXTGLOBAL_H\n\n#include <QtGlobal>\n\n#define QXT_VERSION 0x000600\n#define QXT_VERSION_STR \"0.6.0\"\n\n//--------------------------global macros------------------------------\n\n#ifndef QXT_NO_MACROS\n\n#endif // QXT_NO_MACROS\n\n//--------------------------export macros------------------------------\n\n#define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE\n\n#if !defined(QXT_STATIC)\n#    if defined(BUILD_QXT_CORE)\n#        define QXT_CORE_EXPORT Q_DECL_EXPORT\n#    else\n#        define QXT_CORE_EXPORT Q_DECL_IMPORT\n#    endif\n#else\n#    define QXT_CORE_EXPORT\n#endif // BUILD_QXT_CORE\n \n#if !defined(QXT_STATIC)\n#    if defined(BUILD_QXT_GUI)\n#        define QXT_GUI_EXPORT Q_DECL_EXPORT\n#    else\n#        define QXT_GUI_EXPORT Q_DECL_IMPORT\n#    endif\n#else\n#    define QXT_GUI_EXPORT\n#endif // BUILD_QXT_GUI\n \n#if !defined(QXT_STATIC)\n#    if defined(BUILD_QXT_NETWORK)\n#        define QXT_NETWORK_EXPORT Q_DECL_EXPORT\n#    else\n#        define QXT_NETWORK_EXPORT Q_DECL_IMPORT\n#    endif\n#else\n#    define QXT_NETWORK_EXPORT\n#endif // BUILD_QXT_NETWORK\n \n#if !defined(QXT_STATIC)\n#    if defined(BUILD_QXT_SQL)\n#        define QXT_SQL_EXPORT Q_DECL_EXPORT\n#    else\n#        define QXT_SQL_EXPORT Q_DECL_IMPORT\n#    endif\n#else\n#    define QXT_SQL_EXPORT\n#endif // BUILD_QXT_SQL\n \n#if !defined(QXT_STATIC)\n#    if defined(BUILD_QXT_WEB)\n#        define QXT_WEB_EXPORT Q_DECL_EXPORT\n#    else\n#        define QXT_WEB_EXPORT Q_DECL_IMPORT\n#    endif\n#else\n#    define QXT_WEB_EXPORT\n#endif // BUILD_QXT_WEB\n \n#if !defined(QXT_STATIC)\n#    if defined(BUILD_QXT_BERKELEY)\n#        define QXT_BERKELEY_EXPORT Q_DECL_EXPORT\n#    else\n#        define QXT_BERKELEY_EXPORT Q_DECL_IMPORT\n#    endif\n#else\n#    define QXT_BERKELEY_EXPORT\n#endif // BUILD_QXT_BERKELEY\n\n#if !defined(QXT_STATIC)\n#    if defined(BUILD_QXT_ZEROCONF)\n#        define QXT_ZEROCONF_EXPORT Q_DECL_EXPORT\n#    else\n#        define QXT_ZEROCONF_EXPORT Q_DECL_IMPORT\n#    endif\n#else\n#    define QXT_ZEROCONF_EXPORT\n#endif // QXT_ZEROCONF_EXPORT\n\n#if defined BUILD_QXT_CORE || defined BUILD_QXT_GUI || defined  BUILD_QXT_SQL || defined BUILD_QXT_NETWORK || defined BUILD_QXT_WEB || defined BUILD_QXT_BERKELEY || defined BUILD_QXT_ZEROCONF\n#   define BUILD_QXT\n#endif\n\nQXT_CORE_EXPORT const char* qxtVersion();\n\n#ifndef QT_BEGIN_NAMESPACE\n#define QT_BEGIN_NAMESPACE\n#endif\n\n#ifndef QT_END_NAMESPACE\n#define QT_END_NAMESPACE\n#endif\n\n#ifndef QT_FORWARD_DECLARE_CLASS\n#define QT_FORWARD_DECLARE_CLASS(Class) class Class;\n#endif\n\n/****************************************************************************\n** This file is derived from code bearing the following notice:\n** The sole author of this file, Adam Higerd, has explicitly disclaimed all\n** copyright interest and protection for the content within. This file has\n** been placed in the public domain according to United States copyright\n** statute and case law. In jurisdictions where this public domain dedication\n** is not legally recognized, anyone who receives a copy of this file is\n** permitted to use, modify, duplicate, and redistribute this file, in whole\n** or in part, with no restrictions or conditions. In these jurisdictions,\n** this file shall be copyright (C) 2006-2008 by Adam Higerd.\n****************************************************************************/\n\n#define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface<PUB, PUB##Private> qxt_d;\n#define QXT_DECLARE_PUBLIC(PUB) friend class PUB;\n#define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this);\n#define QXT_D(PUB) PUB##Private& d = qxt_d()\n#define QXT_P(PUB) PUB& p = qxt_p()\n\ntemplate <typename PUB>\nclass QxtPrivate\n{\npublic:\n    virtual ~QxtPrivate()\n    {}\n    inline void QXT_setPublic(PUB* pub)\n    {\n        qxt_p_ptr = pub;\n    }\n\nprotected:\n    inline PUB& qxt_p()\n    {\n        return *qxt_p_ptr;\n    }\n    inline const PUB& qxt_p() const\n    {\n        return *qxt_p_ptr;\n    }\n\nprivate:\n    PUB* qxt_p_ptr;\n};\n\ntemplate <typename PUB, typename PVT>\nclass QxtPrivateInterface\n{\n    friend class QxtPrivate<PUB>;\npublic:\n    QxtPrivateInterface()\n    {\n        pvt = new PVT;\n    }\n    ~QxtPrivateInterface()\n    {\n        delete pvt;\n    }\n\n    inline void setPublic(PUB* pub)\n    {\n        pvt->QXT_setPublic(pub);\n    }\n    inline PVT& operator()()\n    {\n        return *static_cast<PVT*>(pvt);\n    }\n    inline const PVT& operator()() const\n    {\n        return *static_cast<PVT*>(pvt);\n    }\nprivate:\n    QxtPrivateInterface(const QxtPrivateInterface&) { }\n    QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }\n    QxtPrivate<PUB>* pvt;\n};\n\n#endif // QXT_GLOBAL\n"
  },
  {
    "path": "src/qxtglobalshortcut/qxtglobalshortcut.cpp",
    "content": "/****************************************************************************\r\n **\r\n ** Copyright (C) Qxt Foundation. Some rights reserved.\r\n **\r\n ** This file is part of the QxtGui module of the Qxt library.\r\n **\r\n ** This library is free software; you can redistribute it and/or modify it\r\n ** under the terms of the Common Public License, version 1.0, as published\r\n ** by IBM, and/or under the terms of the GNU Lesser General Public License,\r\n ** version 2.1, as published by the Free Software Foundation.\r\n **\r\n ** This file is provided \"AS IS\", without WARRANTIES OR CONDITIONS OF ANY\r\n ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY\r\n ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR\r\n ** FITNESS FOR A PARTICULAR PURPOSE.\r\n **\r\n ** You should have received a copy of the CPL and the LGPL along with this\r\n ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files\r\n ** included with the source distribution for more information.\r\n ** If you did not receive a copy of the licenses, contact the Qxt Foundation.\r\n **\r\n ** <http://libqxt.org>  <foundation@libqxt.org>\r\n **\r\n ****************************************************************************/\r\n#include \"qxtglobalshortcut.h\"\r\n#include \"qxtglobalshortcut_p.h\"\r\n#include <QAbstractEventDispatcher>\r\n#include <QtDebug>\r\n\r\nbool QxtGlobalShortcutPrivate::error = false;\r\nint QxtGlobalShortcutPrivate::ref = 0;\r\n\r\n#if(QT_VERSION<0x050000)//雨后星辰\r\nQAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0;\r\n#endif\r\n\r\nQHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts;\r\n\r\nQxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier)\r\n{\r\n    if (!ref++){\r\n#if(QT_VERSION<0x050000)//雨后星辰\r\n        prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter);\r\n#else\r\n        QAbstractEventDispatcher::instance ()->installNativeEventFilter (this);\r\n#endif\r\n    }\r\n}\r\n\r\nQxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate()\r\n{\r\n    if (!--ref){\r\n#if(QT_VERSION<0x050000)//雨后星辰\r\n        QAbstractEventDispatcher::instance()->setEventFilter(prevEventFilter);\r\n#else\r\n        QAbstractEventDispatcher::instance ()->removeNativeEventFilter (this);\r\n#endif\r\n    }\r\n}\r\n\r\nbool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut)\r\n{\r\n    Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;\r\n    key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]);\r\n    mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods);\r\n    const quint32 nativeKey = nativeKeycode(key);\r\n    const quint32 nativeMods = nativeModifiers(mods);\r\n    const bool res = registerShortcut(nativeKey, nativeMods);\r\n    shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p());\r\n    if (!res)\r\n        qWarning() << \"QxtGlobalShortcut failed to register:\" << QKeySequence(key + mods).toString();\r\n    return res;\r\n}\r\n\r\nbool QxtGlobalShortcutPrivate::unsetShortcut()\r\n{\r\n    const quint32 nativeKey = nativeKeycode(key);\r\n    const quint32 nativeMods = nativeModifiers(mods);\r\n    const bool res = unregisterShortcut(nativeKey, nativeMods);\r\n    shortcuts.remove(qMakePair(nativeKey, nativeMods));\r\n    if (!res)\r\n        qWarning() << \"QxtGlobalShortcut failed to unregister:\" << QKeySequence(key + mods).toString();\r\n    key = Qt::Key(0);\r\n    mods = Qt::KeyboardModifiers(0);\r\n    return res;\r\n}\r\n\r\nvoid QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods)\r\n{\r\n    QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods));\r\n    if (shortcut && shortcut->isEnabled())\r\n        emit shortcut->activated();\r\n}\r\n\r\n/*!\r\n    \\class QxtGlobalShortcut\r\n    \\inmodule QxtGui\r\n    \\brief The QxtGlobalShortcut class provides a global shortcut aka \"hotkey\".\r\n\r\n    A global shortcut triggers even if the application is not active. This\r\n    makes it easy to implement applications that react to certain shortcuts\r\n    still if some other application is active or if the application is for\r\n    example minimized to the system tray.\r\n\r\n    Example usage:\r\n    \\code\r\n    QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window);\r\n    connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility()));\r\n    shortcut->setShortcut(QKeySequence(\"Ctrl+Shift+F12\"));\r\n    \\endcode\r\n\r\n    \\bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication.\r\n */\r\n\r\n/*!\r\n    \\fn QxtGlobalShortcut::activated()\r\n\r\n    This signal is emitted when the user types the shortcut's key sequence.\r\n\r\n    \\sa shortcut\r\n */\r\n\r\n/*!\r\n    Constructs a new QxtGlobalShortcut with \\a parent.\r\n */\r\nQxtGlobalShortcut::QxtGlobalShortcut(QObject* parent)\r\n        : QObject(parent)\r\n{\r\n    QXT_INIT_PRIVATE(QxtGlobalShortcut);\r\n}\r\n\r\n/*!\r\n    Constructs a new QxtGlobalShortcut with \\a shortcut and \\a parent.\r\n */\r\nQxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent)\r\n        : QObject(parent)\r\n{\r\n    QXT_INIT_PRIVATE(QxtGlobalShortcut);\r\n    setShortcut(shortcut);\r\n}\r\n\r\n/*!\r\n    Destructs the QxtGlobalShortcut.\r\n */\r\nQxtGlobalShortcut::~QxtGlobalShortcut()\r\n{\r\n    if (qxt_d().key != 0)\r\n        qxt_d().unsetShortcut();\r\n}\r\n\r\n/*!\r\n    \\property QxtGlobalShortcut::shortcut\r\n    \\brief the shortcut key sequence\r\n\r\n    \\bold {Note:} Notice that corresponding key press and release events are not\r\n    delivered for registered global shortcuts even if they are disabled.\r\n    Also, comma separated key sequences are not supported.\r\n    Only the first part is used:\r\n\r\n    \\code\r\n    qxtShortcut->setShortcut(QKeySequence(\"Ctrl+Alt+A,Ctrl+Alt+B\"));\r\n    Q_ASSERT(qxtShortcut->shortcut() == QKeySequence(\"Ctrl+Alt+A\"));\r\n    \\endcode\r\n */\r\nQKeySequence QxtGlobalShortcut::shortcut() const\r\n{\r\n    return QKeySequence(qxt_d().key | qxt_d().mods);\r\n}\r\n\r\nbool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut)\r\n{\r\n    if (qxt_d().key != 0)\r\n        qxt_d().unsetShortcut();\r\n    return qxt_d().setShortcut(shortcut);\r\n}\r\n\r\n/*!\r\n    \\property QxtGlobalShortcut::enabled\r\n    \\brief whether the shortcut is enabled\r\n\r\n    A disabled shortcut does not get activated.\r\n\r\n    The default value is \\c true.\r\n\r\n    \\sa setDisabled()\r\n */\r\nbool QxtGlobalShortcut::isEnabled() const\r\n{\r\n    return qxt_d().enabled;\r\n}\r\n\r\nvoid QxtGlobalShortcut::setEnabled(bool enabled)\r\n{\r\n    qxt_d().enabled = enabled;\r\n}\r\n\r\n/*!\r\n    Sets the shortcut \\a disabled.\r\n\r\n    \\sa enabled\r\n */\r\nvoid QxtGlobalShortcut::setDisabled(bool disabled)\r\n{\r\n    qxt_d().enabled = !disabled;\r\n}\r\n"
  },
  {
    "path": "src/qxtglobalshortcut/qxtglobalshortcut.h",
    "content": "/****************************************************************************\r\n **\r\n ** Copyright (C) Qxt Foundation. Some rights reserved.\r\n **\r\n ** This file is part of the QxtGui module of the Qxt library.\r\n **\r\n ** This library is free software; you can redistribute it and/or modify it\r\n ** under the terms of the Common Public License, version 1.0, as published\r\n ** by IBM, and/or under the terms of the GNU Lesser General Public License,\r\n ** version 2.1, as published by the Free Software Foundation.\r\n **\r\n ** This file is provided \"AS IS\", without WARRANTIES OR CONDITIONS OF ANY\r\n ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY\r\n ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR\r\n ** FITNESS FOR A PARTICULAR PURPOSE.\r\n **\r\n ** You should have received a copy of the CPL and the LGPL along with this\r\n ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files\r\n ** included with the source distribution for more information.\r\n ** If you did not receive a copy of the licenses, contact the Qxt Foundation.\r\n **\r\n ** <http://libqxt.org>  <foundation@libqxt.org>\r\n **\r\n ****************************************************************************/\r\n#ifndef QXTGLOBALSHORTCUT_H\r\n#define QXTGLOBALSHORTCUT_H\r\n\r\n#include \"qxtglobal.h\"\r\n#include <QObject>\r\n#include <QKeySequence>\r\nclass QxtGlobalShortcutPrivate;\r\n\r\nclass QxtGlobalShortcut : public QObject\r\n{\r\n    Q_OBJECT\r\n    QXT_DECLARE_PRIVATE(QxtGlobalShortcut)\r\n    Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)\r\n    Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)\r\n\r\npublic:\r\n    explicit QxtGlobalShortcut(QObject* parent = 0);\r\n    explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = 0);\r\n    virtual ~QxtGlobalShortcut();\r\n\r\n    QKeySequence shortcut() const;\r\n    bool setShortcut(const QKeySequence& shortcut);\r\n    bool isEnabled() const;\r\n\r\npublic Q_SLOTS:\r\n    void setEnabled(bool enabled = true);\r\n    void setDisabled(bool disabled = true);\r\n\r\nQ_SIGNALS:\r\n    void activated();\r\n};\r\n\r\n#endif // QXTGLOBALSHORTCUT_H\r\n"
  },
  {
    "path": "src/qxtglobalshortcut/qxtglobalshortcut.pri",
    "content": "INCLUDEPATH += $$PWD  \r\nDEPENDPATH += $$PWD  \r\n \r\nHEADERS += $$PWD/qxtglobal.h \\  \r\n           $$PWD/qxtglobalshortcut.h \\  \r\n           $$PWD/qxtglobalshortcut_p.h \\\r\n           $$PWD/myshortcut.h\r\nSOURCES += $$PWD/qxtglobalshortcut.cpp \\\r\n           $$PWD/myshortcut.cpp\r\nwin32{  \r\n    SOURCES += $$PWD/qxtglobalshortcut_win.cpp  \r\n    LIBS += -luser32  \r\n}  \r\nunix{\r\n    QT += x11extras\r\n    LIBS += -lX11\r\n    SOURCES += $$PWD/qxtglobalshortcut_x11.cpp\r\n}\r\nmac{\r\n    SOURCES += $$PWD/qxtglobalshortcut_mac.cpp \r\n}\r\n"
  },
  {
    "path": "src/qxtglobalshortcut/qxtglobalshortcut_mac.cpp",
    "content": "/****************************************************************************\r\n **\r\n ** Copyright (C) Qxt Foundation. Some rights reserved.\r\n **\r\n ** This file is part of the QxtGui module of the Qxt library.\r\n **\r\n ** This library is free software; you can redistribute it and/or modify it\r\n ** under the terms of the Common Public License, version 1.0, as published\r\n ** by IBM, and/or under the terms of the GNU Lesser General Public License,\r\n ** version 2.1, as published by the Free Software Foundation.\r\n **\r\n ** This file is provided \"AS IS\", without WARRANTIES OR CONDITIONS OF ANY\r\n ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY\r\n ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR\r\n ** FITNESS FOR A PARTICULAR PURPOSE.\r\n **\r\n ** You should have received a copy of the CPL and the LGPL along with this\r\n ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files\r\n ** included with the source distribution for more information.\r\n ** If you did not receive a copy of the licenses, contact the Qxt Foundation.\r\n **\r\n ** <http://libqxt.org>  <foundation@libqxt.org>\r\n **\r\n ****************************************************************************/\r\n#include <Carbon/Carbon.h>\r\n#include \"qxtglobalshortcut_p.h\"\r\n#include <QMap>\r\n#include <QHash>\r\n#include <QtDebug>\r\n#include <QApplication>\r\n\r\ntypedef QPair<uint, uint> Identifier;\r\nstatic QMap<quint32, EventHotKeyRef> keyRefs;\r\nstatic QHash<Identifier, quint32> keyIDs;\r\nstatic quint32 hotKeySerial = 0;\r\nstatic bool qxt_mac_handler_installed = false;\r\n\r\nOSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data)\r\n{\r\n    // pass event to the app event filter\r\n    Q_UNUSED(data);\r\n    qApp->macEventFilter(nextHandler, event);\r\n    return noErr;\r\n}\r\n#if(QT_VERSION<0x050000)\r\nbool QxtGlobalShortcutPrivate::eventFilter(void* message)\r\n//bool QxtGlobalShortcutPrivate::macEventFilter(EventHandlerCallRef caller, EventRef event)\r\n{\r\n    EventRef event = (EventRef) message;\r\n    if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed)\r\n    {\r\n        EventHotKeyID keyID;\r\n        GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID);\r\n        Identifier id = keyIDs.key(keyID.id);\r\n        activateShortcut(id.second, id.first);\r\n    }\r\n    return false;\r\n}\r\n#else\r\nbool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray &, void *message, long *)\r\n{\r\n    EventRef event = (EventRef) message;\r\n    if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed)\r\n    {\r\n        EventHotKeyID keyID;\r\n        GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID);\r\n        Identifier id = keyIDs.key(keyID.id);\r\n        activateShortcut(id.second, id.first);\r\n    }\r\n    return false;\r\n}\r\n#endif\r\nquint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)\r\n{\r\n    quint32 native = 0;\r\n    if (modifiers & Qt::ShiftModifier)\r\n        native |= shiftKeyBit;\r\n    if (modifiers & Qt::ControlModifier)\r\n        native |= cmdKey;\r\n    if (modifiers & Qt::AltModifier)\r\n        native |= optionKey;\r\n    if (modifiers & Qt::MetaModifier)\r\n        native |= controlKey;\r\n    if (modifiers & Qt::KeypadModifier)\r\n        native |= kEventKeyModifierNumLockMask;\r\n    return native;\r\n}\r\n\r\nquint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)\r\n{\r\n    UTF16Char ch;\r\n    // Constants found in NSEvent.h from AppKit.framework\r\n    if (key == Qt::Key_Up)\t\t\t\tch = 0xF700;\r\n    else if (key == Qt::Key_Down)\t\tch = 0xF701;\r\n    else if (key == Qt::Key_Left)\t\tch = 0xF702;\r\n    else if (key == Qt::Key_Right)\t\tch = 0xF703;\r\n    else if (key >= Qt::Key_F1 && key <= Qt::Key_F35)\r\n        ch = key - Qt::Key_F1 + 0xF704;\r\n    else if (key == Qt::Key_Insert)\t\tch = 0xF727;\r\n    else if (key == Qt::Key_Delete)\t\tch = 0xF728;\r\n    else if (key == Qt::Key_Home)\t\tch = 0xF729;\r\n    else if (key == Qt::Key_End)\t\t\tch = 0xF72B;\r\n    else if (key == Qt::Key_PageUp)\t\tch = 0xF72C;\r\n    else if (key == Qt::Key_PageDown)\tch = 0xF72D;\r\n    else if (key == Qt::Key_Print)\t\tch = 0xF72E;\r\n    else if (key == Qt::Key_ScrollLock)\tch = 0xF72F;\r\n    else if (key == Qt::Key_Pause)\t\tch = 0xF730;\r\n    else if (key == Qt::Key_SysReq)\t\tch = 0xF731;\r\n    else if (key == Qt::Key_Stop)\t\tch = 0xF734;\r\n    else if (key == Qt::Key_Menu)\t\tch = 0xF735;\r\n    else if (key == Qt::Key_Select)\t\tch = 0xF741;\r\n    else if (key == Qt::Key_Execute)\t\tch = 0xF742;\r\n    else if (key == Qt::Key_Help)\t\tch = 0xF746;\r\n    else if (key == Qt::Key_Mode_switch)\tch = 0xF747;\r\n    else if (key == Qt::Key_Escape)\t\tch = 27;\r\n    else if (key == Qt::Key_Return)\t\tch = 13;\r\n    else if (key == Qt::Key_Enter)\t\tch = 3;\r\n    else if (key == Qt::Key_Tab)\t\t\tch = 9;\r\n    else\t\t\t\t\t\t\t\tch = key;\r\n\r\n    KeyboardLayoutRef layout;\r\n    KeyboardLayoutKind layoutKind;\r\n    KLGetCurrentKeyboardLayout(&layout);\r\n    KLGetKeyboardLayoutProperty(layout, kKLKind, const_cast<const void**>(reinterpret_cast<void**>(&layoutKind)));\r\n\r\n    if (layoutKind == kKLKCHRKind)\r\n    { // no Unicode available\r\n        if (ch > 255) return 0;\r\n\r\n        char* data;\r\n        KLGetKeyboardLayoutProperty(layout, kKLKCHRData, const_cast<const void**>(reinterpret_cast<void**>(&data)));\r\n        int ct = *reinterpret_cast<short*>(data + 258);\r\n        for (int i = 0; i < ct; i++)\r\n        {\r\n            char* keyTable = data + 260 + 128 * i;\r\n            for (int j = 0; j < 128; j++)\r\n            {\r\n                if (keyTable[j] == ch) return j;\r\n            }\r\n        }\r\n\r\n        return 0;\r\n    }\r\n\r\n    char* data;\r\n    KLGetKeyboardLayoutProperty(layout, kKLuchrData, const_cast<const void**>(reinterpret_cast<void**>(&data)));\r\n    UCKeyboardLayout* header = reinterpret_cast<UCKeyboardLayout*>(data);\r\n    UCKeyboardTypeHeader* table = header->keyboardTypeList;\r\n\r\n    for (quint32 i=0; i < header->keyboardTypeCount; i++)\r\n    {\r\n        UCKeyStateRecordsIndex* stateRec = 0;\r\n        if (table[i].keyStateRecordsIndexOffset != 0)\r\n        {\r\n            stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);\r\n            if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;\r\n        }\r\n\r\n        UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);\r\n        if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;\r\n\r\n        for (quint32 j=0; j < charTable->keyToCharTableCount; j++)\r\n        {\r\n            UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);\r\n            for (quint32 k=0; k < charTable->keyToCharTableSize; k++)\r\n            {\r\n                if (keyToChar[k] & kUCKeyOutputTestForIndexMask)\r\n                {\r\n                    long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;\r\n                    if (stateRec && idx < stateRec->keyStateRecordCount)\r\n                    {\r\n                        UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);\r\n                        if (rec->stateZeroCharData == ch) return k;\r\n                    }\r\n                }\r\n                else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE)\r\n                {\r\n                    if (keyToChar[k] == ch) return k;\r\n                }\r\n            } // for k\r\n        } // for j\r\n    } // for i\r\n\r\n    return 0;\r\n}\r\n\r\nbool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)\r\n{\r\n    if (!qxt_mac_handler_installed)\r\n    {\r\n        EventTypeSpec t;\r\n        t.eventClass = kEventClassKeyboard;\r\n        t.eventKind = kEventHotKeyPressed;\r\n        InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL);\r\n    }\r\n\r\n    EventHotKeyID keyID;\r\n    keyID.signature = 'cute';\r\n    keyID.id = ++hotKeySerial;\r\n\r\n    EventHotKeyRef ref = 0;\r\n    bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref);\r\n    if (rv)\r\n    {\r\n        keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id);\r\n        keyRefs.insert(keyID.id, ref);\r\n    }\r\n    qDebug() << ref;\r\n    return rv;\r\n}\r\n\r\nbool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)\r\n{\r\n    Identifier id(nativeMods, nativeKey);\r\n    if (!keyIDs.contains(id)) return false;\r\n\r\n    EventHotKeyRef ref = keyRefs.take(keyIDs[id]);\r\n    keyIDs.remove(id);\r\n    return !UnregisterEventHotKey(ref);\r\n}\r\n"
  },
  {
    "path": "src/qxtglobalshortcut/qxtglobalshortcut_p.h",
    "content": "/****************************************************************************\r\n **\r\n ** Copyright (C) Qxt Foundation. Some rights reserved.\r\n **\r\n ** This file is part of the QxtGui module of the Qxt library.\r\n **\r\n ** This library is free software; you can redistribute it and/or modify it\r\n ** under the terms of the Common Public License, version 1.0, as published\r\n ** by IBM, and/or under the terms of the GNU Lesser General Public License,\r\n ** version 2.1, as published by the Free Software Foundation.\r\n **\r\n ** This file is provided \"AS IS\", without WARRANTIES OR CONDITIONS OF ANY\r\n ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY\r\n ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR\r\n ** FITNESS FOR A PARTICULAR PURPOSE.\r\n **\r\n ** You should have received a copy of the CPL and the LGPL along with this\r\n ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files\r\n ** included with the source distribution for more information.\r\n ** If you did not receive a copy of the licenses, contact the Qxt Foundation.\r\n **\r\n ** <http://libqxt.org>  <foundation@libqxt.org>\r\n **\r\n ****************************************************************************/\r\n#ifndef QXTGLOBALSHORTCUT_P_H\r\n#define QXTGLOBALSHORTCUT_P_H\r\n\r\n#include \"qxtglobalshortcut.h\"\r\n#include <QAbstractEventDispatcher>\r\n#include <QKeySequence>\r\n#include <QHash>\r\n#if(QT_VERSION>=0x050000)//雨后星辰\r\n#include <QAbstractNativeEventFilter>\r\n#endif\r\n\r\nclass QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>\r\n#if(QT_VERSION>=0x050000)\r\n        , public QAbstractNativeEventFilter\r\n#endif\r\n{\r\npublic:\r\n    QXT_DECLARE_PUBLIC(QxtGlobalShortcut)\r\n    QxtGlobalShortcutPrivate();\r\n    ~QxtGlobalShortcutPrivate();\r\n\r\n    bool enabled;\r\n    Qt::Key key;\r\n    Qt::KeyboardModifiers mods;\r\n\r\n    bool setShortcut(const QKeySequence& shortcut);\r\n    bool unsetShortcut();\r\n\r\n    static bool error;\r\n    static int ref;\r\n#if(QT_VERSION<0x050000)//雨后星辰\r\n    static QAbstractEventDispatcher::EventFilter prevEventFilter;\r\n    static bool eventFilter(void* message);\r\n#else\r\n    bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);\r\n#endif\r\nprivate:\r\n    static quint32 nativeKeycode(Qt::Key keycode);\r\n    static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers);\r\n\r\n    static bool registerShortcut(quint32 nativeKey, quint32 nativeMods);\r\n    static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods);\r\n    static void activateShortcut(quint32 nativeKey, quint32 nativeMods);\r\n\r\n    static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts;\r\n};\r\n\r\n#endif // QXTGLOBALSHORTCUT_P_H\r\n"
  },
  {
    "path": "src/qxtglobalshortcut/qxtglobalshortcut_win.cpp",
    "content": "/****************************************************************************\r\n **\r\n ** Copyright (C) Qxt Foundation. Some rights reserved.\r\n **\r\n ** This file is part of the QxtGui module of the Qxt library.\r\n **\r\n ** This library is free software; you can redistribute it and/or modify it\r\n ** under the terms of the Common Public License, version 1.0, as published\r\n ** by IBM, and/or under the terms of the GNU Lesser General Public License,\r\n ** version 2.1, as published by the Free Software Foundation.\r\n **\r\n ** This file is provided \"AS IS\", without WARRANTIES OR CONDITIONS OF ANY\r\n ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY\r\n ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR\r\n ** FITNESS FOR A PARTICULAR PURPOSE.\r\n **\r\n ** You should have received a copy of the CPL and the LGPL along with this\r\n ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files\r\n ** included with the source distribution for more information.\r\n ** If you did not receive a copy of the licenses, contact the Qxt Foundation.\r\n **\r\n ** <http://libqxt.org>  <foundation@libqxt.org>\r\n **\r\n ****************************************************************************/\r\n#include \"qxtglobalshortcut_p.h\"\r\n#include <qt_windows.h>\r\n#include <QDebug>\r\n\r\n#if(QT_VERSION<0x050000)\r\nbool QxtGlobalShortcutPrivate::eventFilter(void* message)\r\n{\r\n    MSG* msg = static_cast<MSG*>(message);\r\n    if (msg->message == WM_HOTKEY)\r\n    {\r\n        const quint32 keycode = HIWORD(msg->lParam);\r\n        const quint32 modifiers = LOWORD(msg->lParam);\r\n        activateShortcut(keycode, modifiers);\r\n    }\r\n    return false;\r\n}\r\n#else\r\nbool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray &, void *message, long *)\r\n{\r\n    MSG* msg = static_cast<MSG*>(message);\r\n    if (msg->message == WM_HOTKEY)\r\n    {\r\n        const quint32 keycode = HIWORD(msg->lParam);\r\n        const quint32 modifiers = LOWORD(msg->lParam);\r\n        activateShortcut(keycode, modifiers);\r\n    }\r\n    return false;\r\n}\r\n#endif\r\nquint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)\r\n{\r\n    // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN\r\n    quint32 native = 0;\r\n    if (modifiers & Qt::ShiftModifier)\r\n        native |= MOD_SHIFT;\r\n    if (modifiers & Qt::ControlModifier)\r\n        native |= MOD_CONTROL;\r\n    if (modifiers & Qt::AltModifier)\r\n        native |= MOD_ALT;\r\n    if (modifiers & Qt::MetaModifier)\r\n        native |= MOD_WIN;\r\n    // TODO: resolve these?\r\n    //if (modifiers & Qt::KeypadModifier)\r\n    //if (modifiers & Qt::GroupSwitchModifier)\r\n    return native;\r\n}\r\n\r\nquint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)\r\n{\r\n    switch (key)\r\n    {\r\n    case Qt::Key_Escape:\r\n        return VK_ESCAPE;\r\n    case Qt::Key_Tab:\r\n    case Qt::Key_Backtab:\r\n        return VK_TAB;\r\n    case Qt::Key_Backspace:\r\n        return VK_BACK;\r\n    case Qt::Key_Return:\r\n    case Qt::Key_Enter:\r\n        return VK_RETURN;\r\n    case Qt::Key_Insert:\r\n        return VK_INSERT;\r\n    case Qt::Key_Delete:\r\n        return VK_DELETE;\r\n    case Qt::Key_Pause:\r\n        return VK_PAUSE;\r\n    case Qt::Key_Print:\r\n        return VK_PRINT;\r\n    case Qt::Key_Clear:\r\n        return VK_CLEAR;\r\n    case Qt::Key_Home:\r\n        return VK_HOME;\r\n    case Qt::Key_End:\r\n        return VK_END;\r\n    case Qt::Key_Left:\r\n        return VK_LEFT;\r\n    case Qt::Key_Up:\r\n        return VK_UP;\r\n    case Qt::Key_Right:\r\n        return VK_RIGHT;\r\n    case Qt::Key_Down:\r\n        return VK_DOWN;\r\n    case Qt::Key_PageUp:\r\n        return VK_PRIOR;\r\n    case Qt::Key_PageDown:\r\n        return VK_NEXT;\r\n    case Qt::Key_F1:\r\n        return VK_F1;\r\n    case Qt::Key_F2:\r\n        return VK_F2;\r\n    case Qt::Key_F3:\r\n        return VK_F3;\r\n    case Qt::Key_F4:\r\n        return VK_F4;\r\n    case Qt::Key_F5:\r\n        return VK_F5;\r\n    case Qt::Key_F6:\r\n        return VK_F6;\r\n    case Qt::Key_F7:\r\n        return VK_F7;\r\n    case Qt::Key_F8:\r\n        return VK_F8;\r\n    case Qt::Key_F9:\r\n        return VK_F9;\r\n    case Qt::Key_F10:\r\n        return VK_F10;\r\n    case Qt::Key_F11:\r\n        return VK_F11;\r\n    case Qt::Key_F12:\r\n        return VK_F12;\r\n    case Qt::Key_F13:\r\n        return VK_F13;\r\n    case Qt::Key_F14:\r\n        return VK_F14;\r\n    case Qt::Key_F15:\r\n        return VK_F15;\r\n    case Qt::Key_F16:\r\n        return VK_F16;\r\n    case Qt::Key_F17:\r\n        return VK_F17;\r\n    case Qt::Key_F18:\r\n        return VK_F18;\r\n    case Qt::Key_F19:\r\n        return VK_F19;\r\n    case Qt::Key_F20:\r\n        return VK_F20;\r\n    case Qt::Key_F21:\r\n        return VK_F21;\r\n    case Qt::Key_F22:\r\n        return VK_F22;\r\n    case Qt::Key_F23:\r\n        return VK_F23;\r\n    case Qt::Key_F24:\r\n        return VK_F24;\r\n    case Qt::Key_Space:\r\n        return VK_SPACE;\r\n    case Qt::Key_Asterisk:\r\n        return VK_MULTIPLY;\r\n    case Qt::Key_Plus:\r\n        return VK_ADD;\r\n    case Qt::Key_Comma:\r\n        return VK_SEPARATOR;\r\n    case Qt::Key_Minus:\r\n        return VK_SUBTRACT;\r\n    case Qt::Key_Slash:\r\n        return VK_DIVIDE;\r\n\r\n        // numbers\r\n    case Qt::Key_0:\r\n    case Qt::Key_1:\r\n    case Qt::Key_2:\r\n    case Qt::Key_3:\r\n    case Qt::Key_4:\r\n    case Qt::Key_5:\r\n    case Qt::Key_6:\r\n    case Qt::Key_7:\r\n    case Qt::Key_8:\r\n    case Qt::Key_9:\r\n        return key;\r\n\r\n        // letters\r\n    case Qt::Key_A:\r\n    case Qt::Key_B:\r\n    case Qt::Key_C:\r\n    case Qt::Key_D:\r\n    case Qt::Key_E:\r\n    case Qt::Key_F:\r\n    case Qt::Key_G:\r\n    case Qt::Key_H:\r\n    case Qt::Key_I:\r\n    case Qt::Key_J:\r\n    case Qt::Key_K:\r\n    case Qt::Key_L:\r\n    case Qt::Key_M:\r\n    case Qt::Key_N:\r\n    case Qt::Key_O:\r\n    case Qt::Key_P:\r\n    case Qt::Key_Q:\r\n    case Qt::Key_R:\r\n    case Qt::Key_S:\r\n    case Qt::Key_T:\r\n    case Qt::Key_U:\r\n    case Qt::Key_V:\r\n    case Qt::Key_W:\r\n    case Qt::Key_X:\r\n    case Qt::Key_Y:\r\n    case Qt::Key_Z:\r\n        return key;\r\n\r\n    default:\r\n        return 0;\r\n    }\r\n}\r\n\r\nbool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)\r\n{\r\n    return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);\r\n}\r\n\r\nbool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)\r\n{\r\n    return UnregisterHotKey(0, nativeMods ^ nativeKey);\r\n}\r\n"
  },
  {
    "path": "src/qxtglobalshortcut/qxtglobalshortcut_x11.cpp",
    "content": "/****************************************************************************\r\n **\r\n ** Copyright (C) Qxt Foundation. Some rights reserved.\r\n **\r\n ** This file is part of the QxtGui module of the Qxt library.\r\n **\r\n ** This library is free software; you can redistribute it and/or modify it\r\n ** under the terms of the Common Public License, version 1.0, as published\r\n ** by IBM, and/or under the terms of the GNU Lesser General Public License,\r\n ** version 2.1, as published by the Free Software Foundation.\r\n **\r\n ** This file is provided \"AS IS\", without WARRANTIES OR CONDITIONS OF ANY\r\n ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY\r\n ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR\r\n ** FITNESS FOR A PARTICULAR PURPOSE.\r\n **\r\n ** You should have received a copy of the CPL and the LGPL along with this\r\n ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files\r\n ** included with the source distribution for more information.\r\n ** If you did not receive a copy of the licenses, contact the Qxt Foundation.\r\n **\r\n ** <http://libqxt.org>  <foundation@libqxt.org>\r\n **\r\n ****************************************************************************/\r\n#include \"qxtglobalshortcut_p.h\"\r\n#include <QX11Info>\r\n#include <X11/Xlib.h>\r\n\r\nstatic int (*original_x_errhandler)(Display* display, XErrorEvent* event);\r\n\r\nstatic int qxt_x_errhandler(Display* display, XErrorEvent *event)\r\n{\r\n    Q_UNUSED(display);\r\n    switch (event->error_code)\r\n    {\r\n        case BadAccess:\r\n        case BadValue:\r\n        case BadWindow:\r\n            if (event->request_code == 33 /* X_GrabKey */ ||\r\n                event->request_code == 34 /* X_UngrabKey */)\r\n            {\r\n                QxtGlobalShortcutPrivate::error = true;\r\n                //TODO:\r\n                //char errstr[256];\r\n                //XGetErrorText(dpy, err->error_code, errstr, 256);\r\n            }\r\n        default:\r\n            return 0;\r\n    }\r\n}\r\n#if(QT_VERSION<0x050000)\r\nbool QxtGlobalShortcutPrivate::eventFilter(void* message)\r\n{\r\n    XEvent* event = static_cast<XEvent*>(message);\r\n    if (event->type == KeyPress)\r\n    {\r\n        XKeyEvent* key = (XKeyEvent*) event;\r\n        activateShortcut(key->keycode, \r\n            // Mod1Mask == Alt, Mod4Mask == Meta\r\n            key->state & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));\r\n    }\r\n    return false;\r\n}\r\n#else\r\nbool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray &, void *message, long *)\r\n{\r\n    XEvent* event = static_cast<XEvent*>(message);\r\n    if (event->type == KeyPress)\r\n    {\r\n        XKeyEvent* key = (XKeyEvent*) event;\r\n        activateShortcut(key->keycode, \r\n            // Mod1Mask == Alt, Mod4Mask == Meta\r\n            key->state & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));\r\n    }\r\n    return false;\r\n}\r\n#endif\r\nquint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)\r\n{\r\n    // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask\r\n    quint32 native = 0;\r\n    if (modifiers & Qt::ShiftModifier)\r\n        native |= ShiftMask;\r\n    if (modifiers & Qt::ControlModifier)\r\n        native |= ControlMask;\r\n    if (modifiers & Qt::AltModifier)\r\n        native |= Mod1Mask;\r\n    // TODO: resolve these?\r\n    //if (modifiers & Qt::MetaModifier)\r\n    //if (modifiers & Qt::KeypadModifier)\r\n    //if (modifiers & Qt::GroupSwitchModifier)\r\n    return native;\r\n}\r\n\r\nquint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)\r\n{\r\n    Display* display = QX11Info::display();\r\n    return XKeysymToKeycode(display, XStringToKeysym(QKeySequence(key).toString().toLatin1().data()));\r\n}\r\n\r\nbool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)\r\n{\r\n    Display* display = QX11Info::display();\r\n    Window window = QX11Info::appRootWindow();\r\n    Bool owner = True;\r\n    int pointer = GrabModeAsync;\r\n    int keyboard = GrabModeAsync;\r\n    error = false;\r\n    original_x_errhandler = XSetErrorHandler(qxt_x_errhandler);\r\n    XGrabKey(display, nativeKey, nativeMods, window, owner, pointer, keyboard);\r\n    XGrabKey(display, nativeKey, nativeMods | Mod2Mask, window, owner, pointer, keyboard); // allow numlock\r\n    XSync(display, False);\r\n    XSetErrorHandler(original_x_errhandler);\r\n    return !error;\r\n}\r\n\r\nbool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)\r\n{\r\n    Display* display = QX11Info::display();\r\n    Window window = QX11Info::appRootWindow();\r\n    error = false;\r\n    original_x_errhandler = XSetErrorHandler(qxt_x_errhandler);\r\n    XUngrabKey(display, nativeKey, nativeMods, window);\r\n    XUngrabKey(display, nativeKey, nativeMods | Mod2Mask, window); // allow numlock\r\n    XSync(display, False);\r\n    XSetErrorHandler(original_x_errhandler);\r\n    return !error;\r\n}\r\n"
  },
  {
    "path": "src/utility/downloadimage.cpp",
    "content": "﻿#include \"downloadimage.h\"\r\n#include <QDebug>\r\n#include <QTimer>\r\n#include \"utility.h\"\r\n#include \"myhttprequest.h\"\r\n\r\nDownloadImage::DownloadImage(QObject *parent):\r\n    QObject(parent)\r\n{\r\n    httpRequest = new MyHttpRequest(this);\r\n}\r\n\r\nDownloadImage::DownloadImage(MyHttpRequest *http, QObject *parent):\r\n    QObject(parent)\r\n{\r\n    httpRequest = http;\r\n}\r\n\r\nMyHttpRequest *DownloadImage::getHttpRequest()\r\n{\r\n    return httpRequest;\r\n}\r\n\r\nQString DownloadImage::imageFormatToString(const QByteArray &array)\r\n{\r\n    QByteArray str = array.toHex ();\r\n    \r\n    if(str.mid (2,6)==\"504e47\")\r\n        return \"png\";\r\n    if(str.mid (12,8)==\"4a464946\")\r\n        return \"jpg\";\r\n    if(str.left (6)==\"474946\")\r\n        return \"gif\";\r\n    if(str.left (4)==\"424d\")\r\n        return \"bmp\";\r\n    return \"\";\r\n}\r\n\r\nvoid DownloadImage::downloadFinished(QNetworkReply *replys)\r\n{\r\n    Data data = queue_data.dequeue ();\r\n    ReplyType type=data.replyType;\r\n    ErrorType error=NoError;\r\n    QString saveName = data.saveName;\r\n    QString savePath = data.savePath;\r\n    QString format = \".\";\r\n    \r\n    if(replys->error() == QNetworkReply::NoError)\r\n    {\r\n        QString imageName = savePath;\r\n        QDir dir(imageName);\r\n        if( !dir.exists () )\r\n            dir.mkpath (imageName);\r\n        QByteArray temp=replys->readAll();\r\n        imageName+=\"/\"+saveName;\r\n        format += imageFormatToString (temp);\r\n        if(format!=\".\"){\r\n            imageName.append (format);\r\n            qDebug()<<\"DownloadImage：要保存的图片名为：\"<<imageName;\r\n        }else{\r\n            qDebug()<<\"DownloadImage:未知的图片格式\"<<temp.toHex ();\r\n            error = NotSupportFormat;\r\n            return;\r\n        }\r\n        QFile file(imageName);\r\n        if(file.open (QIODevice::WriteOnly)){\r\n            file.write (temp);//储存图片\r\n            file.close ();\r\n        }else{\r\n            qDebug()<<\"DownloadImage:图片保存失败\"<<file.errorString ();\r\n            error = SaveError;\r\n        }\r\n    }else{\r\n        error = DownloadError;\r\n    }\r\n    \r\n    if(type == CallbackFun){\r\n#if(QT_VERSION>=0x050000)\r\n        QJSValueList list;\r\n        list<<QJSValue((int)error)<<QJSValue(savePath)<<QJSValue(saveName+format);\r\n        data.callbackFun.call (list);\r\n#else\r\n        QScriptValueList list;\r\n        list<<QScriptValue((int)error)<<QScriptValue(savePath)<<QScriptValue(saveName+format);\r\n        data.callbackFun.call (QScriptValue(), list);\r\n#endif\r\n\r\n    }else if(type == ConnectSlot){\r\n        bool ok=QMetaObject::invokeMethod (data.caller, data.slotName,\r\n                                           Q_ARG(DownloadImage::ErrorType, error),\r\n                                           Q_ARG(QString, savePath), \r\n                                           Q_ARG(QString, saveName+format));\r\n        if(!ok)\r\n            qDebug()<<\"DownloadImage:调用槽\"<<data.slotName<<\"出错\";\r\n    }\r\n}\r\n\r\n#if(QT_VERSION>=0x050000)\r\nvoid DownloadImage::getImage(QJSValue callbackFun, QUrl url, QString savePath, QString saveName)\r\n#else\r\nvoid DownloadImage::getImage(QScriptValue callbackFun, QUrl url, QString savePath, QString saveName)\r\n#endif\r\n{\r\n    bool isFun=false;\r\n#if(QT_VERSION>=0x050000)\r\n    isFun=callbackFun.isCallable ();\r\n#else\r\n    isFun = callbackFun.isFunction ();\r\n#endif\r\n    if((!isFun)||url.toString ()==\"\")\r\n        return;\r\n    \r\n    Data data;\r\n    data.replyType = CallbackFun;\r\n    data.callbackFun = callbackFun;\r\n    data.savePath = savePath;\r\n    data.saveName = saveName;\r\n    queue_data<<data;\r\n    \r\n    httpRequest->get (this, SLOT(downloadFinished(QNetworkReply*)), url);//去获取\r\n}\r\n\r\nvoid DownloadImage::getImage(QObject *caller, QByteArray slotName, QUrl url, QString savePath, QString saveName)\r\n{\r\n    if(caller==NULL||slotName==\"\"||url.toString ()==\"\")\r\n        return;\r\n    \r\n    QRegExp reg(\"[_A-Za-z][_A-Za-z0-9]*\");//提取函数名\r\n    if(reg.indexIn (slotName)>=0){\r\n        slotName = reg.cap (0).toLatin1 ();\r\n        Data data;\r\n        data.replyType = ConnectSlot;\r\n        data.caller = caller;\r\n        data.slotName = slotName;\r\n        data.savePath = savePath;\r\n        data.saveName = saveName;\r\n        queue_data<<data;\r\n        httpRequest->get (this, SLOT(downloadFinished(QNetworkReply*)), url);//去获取\r\n    }else{\r\n        qDebug()<<\"DownloadImage:\"<<slotName<<\"不是槽函数\";\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/utility/downloadimage.h",
    "content": "#ifndef DOWNLOADIMAGE_H\r\n#define DOWNLOADIMAGE_H\r\n\r\n#include <QObject>\r\n#include <QQueue>\r\n#include <QByteArray>\r\n#include <QString>\r\n#include <QImage>\r\n#include <QUrl>\r\n#if(QT_VERSION>=0x050000)\r\n#include <QJSValue>\r\n#include <QJSEngine>\r\n#else\r\n#include <QScriptValue>\r\n#include <QScriptEngine>\r\n#endif\r\n\r\nclass MyHttpRequest;\r\nclass QNetworkReply;\r\nclass DownloadImage : public QObject\r\n{\r\n    Q_OBJECT\r\n    Q_ENUMS(ErrorType)\r\npublic:\r\n    explicit DownloadImage(QObject *parent = 0);\r\n    explicit DownloadImage(MyHttpRequest* http, QObject *parent = 0);\r\n    MyHttpRequest *getHttpRequest();\r\n    \r\n    static QString imageFormatToString(const QByteArray& array);\r\n    \r\n    enum ErrorType{\r\n        NoError,//无错误\r\n        DownloadError,//下载出错\r\n        SaveError,//保存出错\r\n        NotSupportFormat//不支持的图片格式\r\n    };\r\n\r\nprivate:\r\n    enum ReplyType{//回调的几种方式\r\n        CallbackFun,\r\n        ConnectSlot\r\n    };\r\n    struct Data{\r\n        ReplyType replyType;\r\n#if(QT_VERSION>=0x050000)\r\n        QJSValue callbackFun;\r\n#else\r\n        QScriptValue callbackFun;\r\n#endif\r\n        QObject* caller;\r\n        QByteArray slotName;\r\n        QString savePath;\r\n        QString saveName;\r\n    };\r\n    QQueue<Data> queue_data;\r\n    MyHttpRequest* httpRequest;\r\n    \r\nprivate slots:\r\n    void downloadFinished(QNetworkReply *replys);//当图片下载完成的时候调用\r\npublic slots:\r\n#if(QT_VERSION>=0x050000)\r\n    void getImage(QJSValue callbackFun, QUrl url, QString savePath, QString saveName);\r\n#else\r\n    void getImage(QScriptValue callbackFun, QUrl url, QString savePath, QString saveName);\r\n#endif\r\n    void getImage(QObject *caller, QByteArray slotName, QUrl url, QString savePath, QString saveName);\r\n    /*\r\n     * savePath中最后一个目录后面不要加\"/\"，saveName不要带后缀\r\n    */\r\n};\r\n\r\n#endif // DOWNLOADIMAGE_H\r\n"
  },
  {
    "path": "src/utility/myhttprequest.cpp",
    "content": "#include \"myhttprequest.h\"\r\n#include \"utility.h\"\r\n#include \"mynetworkaccessmanagerfactory.h\"\r\n\r\nMyHttpRequest::MyHttpRequest(QObject *parent) :\r\n    QObject(parent)\r\n{\r\n    m_status = Idle;\r\n    manager = new NetworkAccessManager(this);\r\n    connect (manager, SIGNAL(finished(QNetworkReply*)), SLOT(finished(QNetworkReply*)));\r\n}\r\n\r\nMyHttpRequest::RequestStatus MyHttpRequest::status()\r\n{\r\n    return m_status;\r\n}\r\n\r\nvoid MyHttpRequest::setStatus(MyHttpRequest::RequestStatus new_status)\r\n{\r\n    if( new_status!=m_status ) {\r\n        m_status = new_status;\r\n        emit statusChanged();\r\n    }\r\n}\r\n\r\nconst NetworkAccessManager *MyHttpRequest::getNetworkAccessManager()\r\n{\r\n    return manager;\r\n}\r\n\r\nQNetworkRequest* MyHttpRequest::getNetworkRequest()\r\n{\r\n    return &request;\r\n}\r\n\r\nvoid MyHttpRequest::finished(QNetworkReply *reply)\r\n{\r\n    Data temp = queue_replyData.dequeue ();\r\n    ReplyType type=temp.replyType;\r\n    bool isError = !(reply->error () == QNetworkReply::NoError);\r\n    \r\n    if(type==CallbackFun){\r\n#if(QT_VERSION>=0x050000)\r\n        QJSValueList list;\r\n        list.append (QJSValue(isError));\r\n        list.append (QJSValue(isError?reply->errorString ():reply->readAll ()));\r\n        temp.callbackFun.call (list);\r\n#else\r\n        QScriptValueList list;\r\n        list.append (QScriptValue(isError));\r\n        list.append (QScriptValue(isError?reply->errorString ():reply->readAll ()));\r\n        temp.callbackFun.call (QScriptValue(), list);\r\n#endif\r\n    }else if(type==ConnectSlot){\r\n        QObject* obj = temp.caller;\r\n        QByteArray slotName = temp.slotName;\r\n        \r\n        if(obj!=NULL){\r\n            bool ok;//记录调用槽是否成功\r\n            int parameterCount = obj->metaObject()->method(obj->metaObject()->indexOfMethod(slotName)).parameterTypes().length();\r\n            QRegExp reg(\"^[^(]+\");\r\n            reg.indexIn (slotName);\r\n            slotName = reg.cap (0).toLatin1 ();\r\n            if(parameterCount==0){//如果形参个数为0个\r\n                ok = QMetaObject::invokeMethod(obj, slotName);\r\n            }else if(parameterCount==1){\r\n                ok = QMetaObject::invokeMethod(obj, slotName, Q_ARG(QNetworkReply*, reply));\r\n            }else if(parameterCount==2){\r\n                ok = QMetaObject::invokeMethod(obj, slotName, Q_ARG(QVariant, isError), Q_ARG(QVariant, (isError?reply->errorString ():reply->readAll ())));\r\n            }else{\r\n                ok = false;\r\n            }\r\n            if(!ok){\r\n                qDebug()<<\"MyHttpRequest:调用槽\"+slotName+\"失败\";\r\n            }\r\n        }\r\n    }\r\n    send();//继续请求\r\n}\r\n\r\n#if(QT_VERSION>=0x050000)\r\nvoid MyHttpRequest::send(QJSValue callbackFun, QUrl url, QByteArray data, bool highRequest/*=false*/)\r\n#else\r\nvoid MyHttpRequest::send(QScriptValue callbackFun, QUrl url, QByteArray data, bool highRequest/*=false*/)\r\n#endif\r\n{\r\n    bool isFun=false;\r\n#if(QT_VERSION>=0x050000)\r\n    isFun=callbackFun.isCallable ();\r\n#else\r\n    isFun = callbackFun.isFunction ();\r\n#endif\r\n    if((!isFun)||url.toString ()==\"\")\r\n        return;\r\n    if(highRequest){\r\n        new MyHttpRequestPrivate(request, callbackFun, url, data);//进行高优先级的网络请求\r\n    }else {\r\n        requestData request_data;\r\n        request_data.url = url;\r\n        request_data.data = data;\r\n        queue_requestData<<request_data;\r\n        \r\n        Data temp;\r\n        temp.callbackFun = callbackFun;\r\n        temp.replyType = CallbackFun;\r\n        queue_replyData<<temp;\r\n        if(status ()==Idle){\r\n            send();\r\n        }\r\n    }\r\n}\r\n\r\nvoid MyHttpRequest::get(QObject *caller, QByteArray slotName, QUrl url, bool highRequest/*=false*/)\r\n{\r\n    send(caller, slotName, url, \"\", highRequest);\r\n}\r\n\r\nvoid MyHttpRequest::post(QObject *caller, QByteArray slotName, QUrl url, QByteArray data, bool highRequest/*=false*/)\r\n{\r\n    send(caller, slotName, url, data, highRequest);\r\n}\r\n\r\n#if(QT_VERSION>=0x050000)\r\nvoid MyHttpRequest::get(QJSValue callbackFun, QUrl url, bool highRequest/*=false*/)\r\n{\r\n    send (callbackFun, url, \"\", highRequest);\r\n}\r\n\r\nvoid MyHttpRequest::post(QJSValue callbackFun, QUrl url, QByteArray data, bool highRequest/*=false*/)\r\n{\r\n    send (callbackFun, url, data, highRequest);\r\n}\r\n#else\r\nvoid MyHttpRequest::get(QScriptValue callbackFun, QUrl url, bool highRequest/*=false*/)\r\n{\r\n    send (callbackFun, url, \"\", highRequest);\r\n}\r\n\r\nvoid MyHttpRequest::post(QScriptValue callbackFun, QUrl url, QByteArray data, bool highRequest/*=false*/)\r\n{\r\n    send (callbackFun, url, data, highRequest);\r\n}\r\n#endif\r\n\r\nvoid MyHttpRequest::send(QObject *caller, QByteArray slotName, QUrl url, QByteArray data, bool highRequest/*=false*/)\r\n{\r\n    if(caller==NULL||slotName==\"\"||url.toString ()==\"\")\r\n        return;\r\n    if(highRequest){\r\n        new MyHttpRequestPrivate(request, caller, slotName, url, data);//进行高优先级的网络请求\r\n    }else{\r\n        QRegExp reg(\"[_A-Za-z][_A-Za-z0-9]*(.+)$\");//提取函数名\r\n        if(reg.indexIn (slotName)>=0){\r\n            requestData request_data;\r\n            request_data.url = url;\r\n            request_data.data = data;\r\n            queue_requestData<<request_data;\r\n\r\n            Data temp;\r\n            temp.caller = caller;\r\n            slotName = reg.cap (0).toLatin1 ();\r\n            temp.slotName = slotName;\r\n            temp.replyType = ConnectSlot;\r\n            queue_replyData<<temp;\r\n            if(status ()==Idle){\r\n                send();\r\n            }\r\n        }else{\r\n            qDebug()<<reg.errorString ();\r\n            qDebug()<<\"MyHttpRequest:\"<<slotName<<\"不是槽函数\";\r\n        }\r\n    }\r\n}\r\n\r\nvoid MyHttpRequest::abort()\r\n{\r\n    if(!m_reply.isNull ()){\r\n        m_reply->abort ();\r\n    }\r\n}\r\n\r\nvoid MyHttpRequest::send()\r\n{\r\n    //qDebug()<<queue_replyData.count ()<<queue_requestData.count ()<<QThread::currentThread ();\r\n    if( queue_requestData.count ()>0){\r\n        setStatus (Busy);\r\n        requestData temp = queue_requestData.dequeue ();\r\n        request.setUrl (temp.url);\r\n        QByteArray data = temp.data;\r\n        if( data==\"\" )\r\n            m_reply = manager->get (request);\r\n        else\r\n            m_reply = manager->post (request, data);\r\n    }else\r\n        setStatus (Idle);//设置状态为空闲\r\n}\r\n\r\nQString MyHttpRequest::errorString()\r\n{\r\n    return m_reply->errorString ();\r\n}\r\n\r\n#if(QT_VERSION>=0x050000)\r\nMyHttpRequestPrivate::MyHttpRequestPrivate(QNetworkRequest request, QJSValue callbackFun, QUrl url, QByteArray data):\r\n#else\r\nMyHttpRequestPrivate::MyHttpRequestPrivate(QNetworkRequest request, QScriptValue callbackFun, QUrl url, QByteArray data):\r\n#endif\r\n    MyHttpRequest(0)\r\n{\r\n    this->request = request;\r\n    send(callbackFun, url, data, false);\r\n}\r\n\r\nMyHttpRequestPrivate::MyHttpRequestPrivate(QNetworkRequest request, QObject *caller, QByteArray slotName, QUrl url, QByteArray data):\r\n    MyHttpRequest(0)\r\n{\r\n    this->request = request;\r\n    send(caller, slotName, url, data, false);\r\n}\r\n\r\nvoid MyHttpRequestPrivate::finished(QNetworkReply *reply)\r\n{\r\n    MyHttpRequest::finished (reply);\r\n    deleteLater ();//销毁自己\r\n}\r\n"
  },
  {
    "path": "src/utility/myhttprequest.h",
    "content": "#ifndef MYHTTPREQUEST_H\r\n#define MYHTTPREQUEST_H\r\n\r\n#include <QObject>\r\n#include <QtNetwork>\r\n#include <QQueue>\r\n#if(QT_VERSION>=0x050000)\r\n#include <QJSValue>\r\n#include <QJSEngine>\r\n#else\r\n#include <QScriptValue>\r\n#include <QScriptEngine>\r\n#endif\r\n\r\nclass NetworkAccessManager;\r\nclass MyHttpRequest : public QObject\r\n{\r\n    Q_OBJECT\r\n    Q_PROPERTY( RequestStatus status READ status WRITE setStatus NOTIFY statusChanged)\r\n    Q_ENUMS(RequestStatus)\r\n\r\npublic:\r\n    explicit MyHttpRequest(QObject *parent = 0);\r\n    enum RequestStatus{\r\n        Idle,//初始状态\r\n        Busy//请求中\r\n    };\r\n\r\n    const NetworkAccessManager *getNetworkAccessManager();\r\n    QNetworkRequest *getNetworkRequest();\r\nprotected:\r\n    NetworkAccessManager *manager;\r\n    QNetworkRequest request;\r\n    QPointer<QNetworkReply> m_reply;\r\n    \r\n    RequestStatus m_status;\r\n    RequestStatus status();\r\n    void setStatus( RequestStatus new_status );\r\n    \r\n    enum ReplyType{//回调的几种方式\r\n        CallbackFun,\r\n        ConnectSlot\r\n    };\r\n    struct Data{\r\n        ReplyType replyType;\r\n#if(QT_VERSION>=0x050000)\r\n        QJSValue callbackFun;\r\n#else\r\n        QScriptValue callbackFun;\r\n#endif\r\n        QObject* caller;\r\n        QByteArray slotName;\r\n    };\r\n    struct requestData{\r\n        QUrl url;\r\n        QByteArray data;\r\n    };\r\n\r\n    QQueue<Data> queue_replyData;\r\n    QQueue<requestData> queue_requestData;\r\n    \r\n    void send(QObject *caller, QByteArray slotName, QUrl url, QByteArray data=\"\", bool highRequest=false );//highRequest记录是否为高级的网络请求\r\n#if(QT_VERSION>=0x050000)\r\n    void send( QJSValue callbackFun, QUrl url, QByteArray data=\"\", bool highRequest=false );\r\n#else\r\n    void send( QScriptValue callbackFun, QUrl url, QByteArray data=\"\", bool highRequest=false );\r\n#endif\r\nprotected slots:\r\n    virtual void finished( QNetworkReply *reply );\r\n    void send();\r\nsignals:\r\n    void statusChanged();\r\npublic slots:\r\n    void get(QObject *caller, QByteArray slotName, QUrl url, bool highRequest=false );\r\n    void post(QObject *caller, QByteArray slotName, QUrl url, QByteArray data=\"\", bool highRequest=false );\r\n#if(QT_VERSION>=0x050000)\r\n    void get(QJSValue callbackFun, QUrl url, bool highRequest=false );\r\n    void post(QJSValue callbackFun, QUrl url, QByteArray data=\"\", bool highRequest=false );\r\n#else\r\n    void get(QScriptValue callbackFun, QUrl url, bool highRequest=false );\r\n    void post(QScriptValue callbackFun, QUrl url, QByteArray data=\"\", bool highRequest=false );\r\n#endif\r\n    void abort();//取消当前网络请求\r\n    QString errorString();\r\n};\r\n\r\nclass MyHttpRequestPrivate : public MyHttpRequest\r\n{\r\n    Q_OBJECT\r\nprivate:\r\n#if(QT_VERSION>=0x050000)\r\n    explicit MyHttpRequestPrivate(QNetworkRequest request, QJSValue callbackFun, QUrl url, QByteArray data);\r\n#else\r\n    explicit MyHttpRequestPrivate(QNetworkRequest request, QScriptValue callbackFun, QUrl url, QByteArray data);\r\n#endif\r\n    explicit MyHttpRequestPrivate(QNetworkRequest request, QObject *caller, QByteArray slotName, QUrl url, QByteArray data);\r\n    friend class MyHttpRequest;\r\nprivate slots:\r\n    void finished( QNetworkReply *reply );\r\n};\r\n\r\n#endif // MYHTTPREQUEST_H\r\n"
  },
  {
    "path": "src/utility/mynetworkaccessmanagerfactory.cpp",
    "content": "#include \"mynetworkaccessmanagerfactory.h\"\r\n#include <QUrl>\r\n#include <QDebug>\r\n\r\nMyNetworkAccessManagerFactory::MyNetworkAccessManagerFactory(QObject *parent) :\r\n    QObject(parent)\r\n{\r\n    m_networkManager = new NetworkAccessManager(this);\r\n    connect(m_networkManager,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),this,SLOT(onIgnoreSSLErrors(QNetworkReply*,QList<QSslError>)));\r\n}\r\n\r\nQNetworkAccessManager* MyNetworkAccessManagerFactory::create(QObject *parent)\r\n{\r\n    QMutexLocker lock(&mutex);\r\n    Q_UNUSED(lock);\r\n    QNetworkAccessManager* manager = new NetworkAccessManager(parent);\r\n    \r\n    return manager;\r\n}\r\n\r\nvoid MyNetworkAccessManagerFactory::onIgnoreSSLErrors(QNetworkReply *reply, QList<QSslError> error)\r\n{\r\n    qDebug()<<error;\r\n    reply->ignoreSslErrors(error);\r\n}\r\n\r\nNetworkAccessManager::NetworkAccessManager(QObject *parent) :\r\n    QNetworkAccessManager(parent)\r\n{\r\n    QNetworkCookieJar* cookieJar = NetworkCookieJar::GetInstance();\r\n    setCookieJar(cookieJar);\r\n    cookieJar->setParent(0);\r\n}\r\n\r\nQNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData)\r\n{\r\n    QNetworkRequest req(request);\r\n    QSslConfiguration config;\r\n\r\n    config.setPeerVerifyMode(QSslSocket::VerifyNone);\r\n    config.setProtocol(QSsl::TlsV1_0);\r\n    req.setSslConfiguration(config);\r\n    // set user-agent\r\n    if (op == PostOperation){\r\n        req.setRawHeader(\"User-Agent\", \"IDP\");\r\n    } else {\r\n        req.setRawHeader(\"User-Agent\", \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36 LBBROWSER\");\r\n    }\r\n    \r\n    QNetworkReply *reply = QNetworkAccessManager::createRequest(op, req, outgoingData);\r\n    \r\n    return reply;\r\n}\r\n\r\nNetworkCookieJar::NetworkCookieJar(QObject *parent) :\r\n    QNetworkCookieJar(parent)\r\n{\r\n    //keepAliveCookie = QNetworkCookie(\"ka\", \"open\");\r\n    load ();\r\n}\r\n\r\nNetworkCookieJar::~NetworkCookieJar()\r\n{\r\n}\r\n\r\nvoid NetworkCookieJar::load()\r\n{\r\n    QMutexLocker lock(&mutex);\r\n    Q_UNUSED(lock);\r\n\r\n}\r\n\r\nNetworkCookieJar* NetworkCookieJar::GetInstance()\r\n{\r\n    static NetworkCookieJar cookieJar;\r\n    return &cookieJar;\r\n}\r\n\r\nvoid NetworkCookieJar::clearCookies()\r\n{\r\n    QList<QNetworkCookie> emptyList;\r\n    setAllCookies(emptyList);\r\n}\r\n\r\nQList<QNetworkCookie> NetworkCookieJar::cookiesForUrl(const QUrl &url) const\r\n{\r\n    QMutexLocker lock(&mutex);\r\n    Q_UNUSED(lock);\r\n    QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url);\r\n    return cookies;\r\n}\r\n\r\nbool NetworkCookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)\r\n{\r\n    QMutexLocker lock(&mutex);\r\n    Q_UNUSED(lock);\r\n    return QNetworkCookieJar::setCookiesFromUrl(cookieList, url);\r\n}\r\n\r\nQList<QNetworkCookie> NetworkCookieJar::cookies() const\r\n{\r\n    return allCookies ();\r\n}\r\n"
  },
  {
    "path": "src/utility/mynetworkaccessmanagerfactory.h",
    "content": "#ifndef MYNETWORKACCESSMANAGERFACTORY_H\r\n#define MYNETWORKACCESSMANAGERFACTORY_H\r\n\r\n#include <QtQuick>\r\n#include <QtNetwork>\r\n#include <QSslConfiguration>\r\n\r\nclass MyNetworkAccessManagerFactory : public QObject,public QQmlNetworkAccessManagerFactory\r\n{\r\n    Q_OBJECT\r\npublic:\r\n    explicit MyNetworkAccessManagerFactory( QObject *parent = 0 );\r\n    virtual QNetworkAccessManager* create(QObject *parent);\r\npublic slots:\r\n    void onIgnoreSSLErrors(QNetworkReply* reply,QList<QSslError> error);\r\nprivate:\r\n    QMutex mutex;\r\n    QNetworkAccessManager* m_networkManager;\r\n};\r\n\r\nclass NetworkAccessManager : public QNetworkAccessManager\r\n{\r\n    Q_OBJECT\r\n\r\npublic:\r\n    explicit NetworkAccessManager(QObject *parent = 0);\r\nprotected:\r\n    QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData);\r\n};\r\n\r\nclass NetworkCookieJar : public QNetworkCookieJar\r\n{\r\npublic:\r\n    static NetworkCookieJar* GetInstance();\r\n    void clearCookies();\r\n\r\n    virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;\r\n    virtual bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);\r\n    QList<QNetworkCookie> cookies() const;\r\nprivate:\r\n    explicit NetworkCookieJar(QObject *parent = 0);\r\n    ~NetworkCookieJar();\r\n    void load();\r\n    mutable QMutex mutex;\r\n    //QNetworkCookie keepAliveCookie;\r\n};\r\n\r\n#endif // MYNETWORKACCESSMANAGERFACTORY_H\r\n"
  },
  {
    "path": "src/utility/texteditplaygif.cpp",
    "content": "#include \"texteditplaygif.h\"\r\n#include <QRegExp>\r\n#include <QLabel>\r\n#include <QMovie>\r\n#include <QTextImageFormat>\r\n#include <QTextCursor>\r\n#include <QDebug>\r\n#include <QDir>\r\n#include <private/qquicktextedit_p.h>\r\n#include <QtConcurrent>\r\n\r\nTextEditPlayGif::TextEditPlayGif(QObject *parent) :\r\n    QObject(parent)\r\n{\r\n    m_enabled=true;\r\n}\r\n\r\nQQuickTextEdit *TextEditPlayGif::target() const\r\n{\r\n    return m_target.data ();\r\n}\r\n\r\nQUrl TextEditPlayGif::cachePath() const\r\n{\r\n    return m_cachePath;\r\n}\r\n\r\nbool TextEditPlayGif::enabled() const\r\n{\r\n    return m_enabled;\r\n}\r\n\r\nvoid TextEditPlayGif::setTarget(QQuickTextEdit *arg)\r\n{\r\n    if (m_target == arg)\r\n        return;\r\n    \r\n    disconnect (m_target, SIGNAL(textChanged()), this, SLOT(onTextChanged()));\r\n    m_target = arg;\r\n    connect (m_target, SIGNAL(textChanged()), SLOT(onTextChanged()));\r\n    emit targetChanged(arg);\r\n}\r\n\r\nvoid TextEditPlayGif::setCachePath(QUrl arg)\r\n{\r\n    if (m_cachePath == arg)\r\n        return;\r\n    \r\n    m_cachePath = arg;\r\n    emit cachePathChanged(arg);\r\n}\r\n\r\nvoid TextEditPlayGif::removeErrorUrl(const QString &url)\r\n{\r\n    list_errorUrl.removeOne (url);\r\n}\r\n\r\nvoid TextEditPlayGif::setEnabled(bool arg)\r\n{\r\n    if (m_enabled == arg)\r\n        return;\r\n    \r\n    m_enabled = arg;\r\n    if(arg){\r\n        startAllMovie ();//启动所有动画\r\n        connect (m_target, SIGNAL(textChanged()), this, SLOT(onTextChanged()));//启动分析\r\n    }else{\r\n        disconnect (m_target, SIGNAL(textChanged()), this, SLOT(onTextChanged()));//停止分析\r\n        stopAllMovie ();//停止所有动画\r\n    }\r\n    emit enabledChanged(arg);\r\n}\r\n\r\nvoid TextEditPlayGif::clearMovie()\r\n{\r\n    foreach (MovieData data, list_movie) {\r\n        data.movie->deleteLater ();\r\n    }\r\n    list_movie.clear ();\r\n}\r\n\r\nvoid TextEditPlayGif::addMovie(QMovie *movie, const QString &url, const QString &gif_name, QSize size)\r\n{\r\n    MovieData data;\r\n    data.movie=movie;\r\n    data.url=url;\r\n    data.gifName=gif_name;\r\n    data.size=size;\r\n    list_movie<<data;\r\n}\r\n\r\nQString TextEditPlayGif::getUrlByMovie(QMovie *movie)\r\n{\r\n    foreach (MovieData data, list_movie) {\r\n        if(data.movie==movie)\r\n            return data.url;\r\n    }\r\n    return \"\";\r\n}\r\n\r\nQString TextEditPlayGif::getGifNameByMovie(QMovie *movie)\r\n{\r\n    foreach (MovieData data, list_movie) {\r\n        if(data.movie==movie)\r\n            return data.gifName;\r\n    }\r\n    return \"\";\r\n}\r\n\r\nTextEditPlayGif::MovieData *TextEditPlayGif::getDataByGifNameAndSize(const QString &name, QSize size)\r\n{\r\n    for(int i=0;i<list_movie.size ();++i){\r\n        MovieData* data = &list_movie[i];\r\n        if(data->gifName==name&&data->size==size)\r\n            return data;\r\n    }\r\n    return NULL;\r\n}\r\n\r\nTextEditPlayGif::MovieData *TextEditPlayGif::getDataByMovie(const QMovie *movie)\r\n{\r\n    for(int i=0;i<list_movie.size ();++i){\r\n        MovieData* data = &list_movie[i];\r\n        if(data->movie==movie)\r\n            return data;\r\n    }\r\n    return NULL;\r\n}\r\n\r\nvoid TextEditPlayGif::setUrlByMovie(QMovie *movie, const QString &url)\r\n{\r\n    for(int i=0;i<list_movie.size ();++i){\r\n        MovieData* data = &list_movie[i];\r\n        if(data->movie==movie)\r\n            data->url=url;\r\n    }\r\n}\r\n\r\nbool TextEditPlayGif::isErrorUrl(const QString url)\r\n{\r\n    foreach (QString str, list_errorUrl) {\r\n        if(str==url){\r\n            return true;\r\n        }\r\n    }\r\n    return false;\r\n}\r\n\r\nvoid TextEditPlayGif::addErrorUrl(const QString url)\r\n{\r\n    if(!isErrorUrl (url))\r\n        list_errorUrl<<url;\r\n    emit error (url+\"文件读取失败\");\r\n}\r\n\r\nvoid TextEditPlayGif::startAllMovie()\r\n{\r\n    for(int i=0;i<list_movie.size ();++i){\r\n        MovieData* data = &list_movie[i];\r\n        if(data->movie->state () != QMovie::Running)\r\n            data->movie->start ();\r\n    }\r\n}\r\n\r\nvoid TextEditPlayGif::stopAllMovie()\r\n{\r\n    for(int i=0;i<list_movie.size ();++i){\r\n        MovieData* data = &list_movie[i];\r\n        if(data->movie->state () == QMovie::Running)\r\n            data->movie->stop ();\r\n    }\r\n}\r\n\r\nvoid TextEditPlayGif::setTextEditContent(const QString &data)\r\n{\r\n    int pos = m_target->cursorPosition ();\r\n    int select_start = m_target->selectionStart ();\r\n    int select_end = m_target->selectionEnd ();\r\n    m_target->setText (data);\r\n    m_target->setCursorPosition (pos);\r\n    m_target->select (select_start, select_end);\r\n}\r\n\r\nvoid TextEditPlayGif::onTextChanged()\r\n{\r\n    QString content = m_target->text ();\r\n    if((content==old_content))\r\n        return;\r\n    old_content = content;\r\n    //qDebug()<<content;\r\n    \r\n    QRegExp reg(\"<img src=\\\"[^\\\"]+.gif\\\".+/>\");\r\n    reg.setMinimal (true);\r\n    reg.indexIn (content);\r\n    \r\n    foreach (QString img, reg.capturedTexts ()) {\r\n        if(img==\"\")\r\n            break;\r\n        //qDebug()<<img;\r\n        QRegExp reg(\"src=\\\".+\\\"\");\r\n        reg.setMinimal (true);\r\n        \r\n        QRegExp reg_width(\"width=\\\"\\\\d+\\\"\");\r\n        reg_width.setMinimal (true);\r\n        int width=-1;\r\n        if(reg_width.indexIn (img)>=0){//如果设置了width\r\n            QString width_str = reg_width.cap (0);\r\n            width_str.replace (\"width=\\\"\",\"\");\r\n            width_str = width_str.left (width_str.size ()-1);\r\n            width = width_str.toInt ();\r\n        }\r\n        QRegExp reg_height(\"height=\\\"\\\\d+\\\"\");\r\n        reg_height.setMinimal (true);\r\n        int height=-1;\r\n        if(reg_height.indexIn (img)>=0){//如果设置了width\r\n            QString height_str = reg_height.cap (0);\r\n            height_str.replace (\"height=\\\"\",\"\");\r\n            height_str = height_str.left (height_str.size ()-1);\r\n            height = height_str.toInt ();\r\n        }\r\n        \r\n        if(reg.indexIn (img)>=0){//如果src存在\r\n            QString src = reg.cap (0);\r\n            if(src==\"\")\r\n                break;\r\n            img = src;\r\n            src = src.mid (5, src.size ()-6);\r\n            QString gifName=\"\";\r\n            foreach (QChar ch, src) {\r\n                if(ch.isLetter ()||ch.isNumber ())\r\n                    gifName.append (ch);\r\n            }\r\n            \r\n            QUrl url(src);\r\n            if(url.isLocalFile ())\r\n                src = url.toLocalFile ();\r\n            else if(src.left (3)==\"qrc\")\r\n                src=src.mid (3);\r\n            if(isErrorUrl (src))\r\n                break;\r\n            QImage image;\r\n            if(image.load (src)){\r\n                if(width==-1)\r\n                    width = image.width ();\r\n                if(height==-1)\r\n                    height = image.height ();\r\n            }else{\r\n                addErrorUrl (src);\r\n                break;\r\n            }\r\n            MovieData* data = getDataByGifNameAndSize (gifName, QSize(width, height));\r\n            if(data!=NULL){\r\n                QString html = m_target->text ().replace (img, data->url);\r\n                setTextEditContent (html);\r\n            }else{\r\n                QMovie *movie=new QMovie(src, \"\", this);\r\n                movie->setCacheMode(QMovie::CacheAll);\r\n                addMovie (movie, img, gifName, QSize(width, height));\r\n                connect (movie, SIGNAL(frameChanged(int)), SLOT(onMovie(int)));\r\n                connect (movie, SIGNAL(finished()), SLOT(onMovieFinished()));\r\n                movie->start ();\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nvoid saveImage(const QString& name, QImage image)\r\n{\r\n    image.save (name);\r\n}\r\n\r\nvoid TextEditPlayGif::onMovie(int frame)\r\n{\r\n    QMovie* movie = qobject_cast<QMovie*>(sender());\r\n    MovieData* movie_data = getDataByMovie (movie);\r\n    \r\n    if(movie&&movie_data&&movie_data->url!=\"\"){\r\n        QString name = QDir::homePath ()+\"/webqq/cacheImage/\"+movie_data->gifName+\"/\";\r\n        QDir dir;\r\n        if(dir.mkpath (name)){//创建路径\r\n            QImage image = movie->currentImage ();\r\n            name.append (QString::number (frame)+\r\n                         QString::number (movie_data->size.width ())+\r\n                         QString::number (movie_data->size.height ())+\r\n                         \".png\");\r\n                \r\n            if(QFile::exists (name)){//如果存在\r\n                name = \"src=\\\"file:///\"+name+\"\\\"\";\r\n                //qDebug()<<name;\r\n                QString data = m_target->text ().replace (movie_data->url, name);\r\n                //qDebug()<<m_target->text ()<<data;\r\n                setUrlByMovie (movie, name);\r\n                setTextEditContent (data);\r\n            }else{\r\n                image = image.scaled (movie_data->size, Qt::KeepAspectRatio, Qt::SmoothTransformation);\r\n                QtConcurrent::run(saveImage, name, image);\r\n            }\r\n        }else{\r\n            qDebug()<<\"TextEditPlayGif:路径\"<<name<<\"创建失败\";\r\n        }\r\n    }\r\n}\r\n\r\nvoid TextEditPlayGif::onMovieFinished()\r\n{\r\n    if(!m_enabled)\r\n        return;\r\n    \r\n    QMovie* movie = qobject_cast<QMovie*>(sender());\r\n    if(movie!=NULL&&movie->currentFrameNumber ()!=-1)\r\n        movie->start ();\r\n}\r\n"
  },
  {
    "path": "src/utility/texteditplaygif.h",
    "content": "#ifndef TEXTEDITPLAYGIF_H\r\n#define TEXTEDITPLAYGIF_H\r\n\r\n#include <QObject>\r\n#include <QQuickTextDocument>\r\n#include <QList>\r\n#include <QThread>\r\n#include <QPointer>\r\n#include <QUrl>\r\n\r\nclass QQuickTextEdit;\r\nclass TextEditPlayGif : public QObject\r\n{\r\n    Q_OBJECT\r\n    \r\n    Q_PROPERTY(QQuickTextEdit* target READ target WRITE setTarget NOTIFY targetChanged)\r\n    Q_PROPERTY(QUrl cachePath READ cachePath WRITE setCachePath NOTIFY cachePathChanged)//此属性暂时未使用\r\n    Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)\r\n    \r\npublic:\r\n    TextEditPlayGif(QObject *parent=0);\r\n    \r\n    QQuickTextEdit* target() const;\r\n    QUrl cachePath() const;\r\n    bool enabled() const;\r\n    \r\nprivate:\r\n    struct MovieData{\r\n        QMovie* movie;\r\n        QString url;\r\n        QString gifName;\r\n        QSize size;\r\n    };\r\n    \r\n    QPointer<QQuickTextEdit> m_target;\r\n    QList<MovieData> list_movie;\r\n    QStringList list_errorUrl;//记录那些解析出错的gif的路径\r\n    QUrl m_cachePath;\r\n    QString old_content;\r\n    bool m_enabled;\r\n    \r\n    void clearMovie();\r\n    void addMovie(QMovie *movie, const QString &url, const QString& gif_name, QSize size);\r\n    QString getUrlByMovie(QMovie* movie);\r\n    QString getGifNameByMovie(QMovie* movie);\r\n    MovieData* getDataByGifNameAndSize(const QString& name, QSize size);\r\n    MovieData* getDataByMovie(const QMovie* movie);\r\n    void setUrlByMovie(QMovie* movie, const QString &url);\r\n    \r\n    bool isErrorUrl(const QString url);\r\n    void addErrorUrl(const QString url);\r\n    \r\n    void startAllMovie();\r\n    void stopAllMovie();\r\n    \r\n    void setTextEditContent(const QString& data);\r\npublic slots:\r\n    void onTextChanged();\r\nprivate slots:\r\n    void onMovie(int frame);\r\n    void onMovieFinished();\r\nsignals:\r\n    void targetChanged(QQuickTextEdit* arg);\r\n    void cachePathChanged(QUrl arg);\r\n    void error(const QString& errorString);\r\n    void enabledChanged(bool arg);\r\n    \r\npublic slots:\r\n    void setTarget(QQuickTextEdit* arg);\r\n    void setCachePath(QUrl arg);\r\n    \r\n    void removeErrorUrl(const QString& url);\r\n    void setEnabled(bool arg);\r\n};\r\n\r\n#endif // TEXTEDITPLAYGIF_H\r\n"
  },
  {
    "path": "src/utility/utility.cpp",
    "content": "#include \"utility.h\"\r\n#include <QDebug>\r\n#include <QtConcurrent>\r\n#include <QApplication>\r\n#include \"mynetworkaccessmanagerfactory.h\"\r\n#include \"downloadimage.h\"\r\n#include \"myhttprequest.h\"\r\n\r\nUtility *Utility::createUtilityClass()\r\n{\r\n    static Utility my_utility;\r\n    return &my_utility;\r\n}\r\n\r\nUtility::Utility(QObject *parent) :\r\n    QObject(parent)\r\n{\r\n    qmlRegisterType<UtilityPrivate>(\"utility\", 1, 0, \"Utility\");\r\n\r\n    http_request = new MyHttpRequest(this);\r\n    download_image = new DownloadImage(this);\r\n    connect (&networkConfigurationManager, &QNetworkConfigurationManager::onlineStateChanged,\r\n             this, &Utility::networkOnlineStateChanged);\r\n}\r\n\r\nUtility::~Utility()\r\n{\r\n}\r\n\r\nchar Utility::numToStr(int num)\r\n{\r\n    QByteArray str=\"QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm\";\r\n    return str[num%str.size ()];\r\n}\r\n\r\nQByteArray Utility::strZoarium(const QByteArray &str)\r\n{\r\n    QByteArray result;\r\n    for(int i=0;i<str.size ();++i){\r\n        char ch = (char)str[i];\r\n        int ch_ascii = (int)ch;\r\n        if(ch<='9'&&ch>='0'){//如果是数字\r\n            result.append (ch);\r\n        }else{//如果不是数字\r\n            if(ch_ascii>=0)\r\n                result.append (numToStr (ch_ascii)).append (QByteArray::number (ch_ascii)).append (numToStr (ch_ascii*2));\r\n        }\r\n    }\r\n    return result;\r\n}\r\n\r\nQByteArray Utility::unStrZoarium(const QByteArray &str)\r\n{\r\n    QByteArray result=\"\";\r\n    for(int i=0;i<str.size ();){\r\n        char ch = (char)str[i];\r\n        if(ch<='9'&&ch>='0'){//如果是数字\r\n            result.append (ch);\r\n            i++;\r\n        }else{//如果是其他\r\n            QRegExp regexp(\"[^0-9]\");\r\n            int pos = QString(str).indexOf (regexp, i+1);\r\n            if(pos>0){\r\n                int num = str.mid (i+1, pos-i-1).toInt ();\r\n                if(num>=0)\r\n                    result.append ((char)num);\r\n                i=pos+1;\r\n            }else{\r\n                //qDebug()<<\"数据有错\";\r\n                i++;\r\n            }\r\n        }\r\n    }\r\n    return result;\r\n}\r\n\r\nQByteArray Utility::fillContent(const QByteArray &str, int length)\r\n{\r\n    if(length>0){\r\n        QByteArray fill_size = QByteArray::number (length);\r\n        if(fill_size.size ()==1)\r\n            fill_size=\"00\"+fill_size;\r\n        else if(fill_size.size ()==2)\r\n            fill_size=\"0\"+fill_size;\r\n        for(int i=0;i<length;++i){\r\n            fill_size.append (\"0\");\r\n        }\r\n        return fill_size+str;\r\n    }else{\r\n        return \"000\"+str;\r\n    }\r\n}\r\n\r\nvoid Utility::consoleLog(QString str)\r\n{\r\n    qDebug()<<\"c++:\"+str;\r\n}\r\n\r\nQString Utility::getCookie(QString cookieName)\r\n{\r\n    QList<QNetworkCookie> temp = NetworkCookieJar::GetInstance ()->cookies ();\r\n    foreach( QNetworkCookie cookie, temp ) {\r\n        if( cookie.name () == cookieName)\r\n            return cookie.value ();\r\n    }\r\n    return \"\";\r\n}\r\n\r\nQQmlApplicationEngine *Utility::qmlEngine()\r\n{\r\n    return engine;\r\n}\r\n\r\nMyHttpRequest *Utility::getHttpRequest()\r\n{\r\n    return http_request;\r\n}\r\n\r\nDownloadImage *Utility::getDownloadImage()\r\n{\r\n    return download_image;\r\n}\r\n\r\nbool Utility::networkIsOnline() const\r\n{\r\n    return networkConfigurationManager.isOnline ();\r\n}\r\n\r\nvoid Utility::setQmlEngine(QQmlApplicationEngine *new_engine)\r\n{\r\n    engine = new_engine;\r\n    if(engine){\r\n        engine->rootContext ()->setContextProperty (\"utility\", this);\r\n    }\r\n}\r\n\r\nvoid Utility::initUtility(QSettings *settings, QQmlApplicationEngine *qmlEngine)\r\n{\r\n    setQSettings (settings);\r\n    setQmlEngine (qmlEngine);\r\n}\r\n\r\nQPoint Utility::mouseDesktopPos()\r\n{\r\n    return QCursor::pos ();\r\n}\r\n\r\nvoid Utility::setQSettings(QSettings *settings)\r\n{\r\n    if(settings)\r\n        mysettings = settings;\r\n}\r\n\r\nvoid Utility::setValue(const QString &key, const QVariant &value)\r\n{\r\n    if( mysettings )\r\n        mysettings->setValue (key, value);\r\n    else\r\n        qDebug()<<\"mysetting=NULL\";\r\n}\r\n\r\nQVariant Utility::value(const QString &key, const QVariant &defaultValue) const\r\n{\r\n    if( mysettings )\r\n        return mysettings->value (key, defaultValue);\r\n    else{\r\n        qDebug()<<\"mysetting=NULL\";\r\n        return QVariant(\"\");\r\n    }\r\n}\r\n\r\nvoid Utility::removeValue(const QString &key)\r\n{\r\n    if( mysettings )\r\n        mysettings->remove (key);\r\n    else\r\n        qDebug()<<\"mysetting=NULL\";\r\n}\r\n\r\nvoid Utility::loadQml(QUrl url)\r\n{\r\n    if(engine)\r\n        engine->load (url);\r\n}\r\n#if(QT_VERSION>=0x050000)\r\nvoid Utility::downloadImage(QJSValue callbackFun, QUrl url, QString savePath, QString saveName)\r\n{\r\n    download_image->getImage (callbackFun, url, savePath, saveName);\r\n}\r\n\r\nvoid Utility::httpGet(QJSValue callbackFun, QUrl url, bool highRequest)\r\n{\r\n    http_request->get (callbackFun, url, highRequest);\r\n}\r\n\r\nvoid Utility::httpPost(QJSValue callbackFun, QUrl url, QByteArray data, bool highRequest)\r\n{\r\n    http_request->post (callbackFun, url, data, highRequest);\r\n}\r\n#else\r\nvoid Utility::downloadImage(QScriptValue callbackFun, QUrl url, QString savePath, QString saveName)\r\n{\r\n    download_image->getImage (callbackFun, url, savePath, saveName);\r\n}\r\n\r\nvoid Utility::httpGet(QScriptValue callbackFun, QUrl url, bool highRequest)\r\n{\r\n    http_request->get (callbackFun, url, highRequest);\r\n}\r\n\r\nvoid Utility::httpPost(QScriptValue callbackFun, QUrl url, QByteArray data, bool highRequest)\r\n{\r\n    http_request->post (callbackFun, url, data, highRequest);\r\n}\r\n#endif\r\nvoid Utility::downloadImage(QObject *caller, QByteArray slotName, QUrl url, QString savePath, QString saveName)\r\n{\r\n    download_image->getImage (caller, slotName, url, savePath, saveName);\r\n}\r\n\r\nvoid Utility::httpGet(QObject *caller, QByteArray slotName, QUrl url, bool highRequest)\r\n{\r\n    http_request->get (caller, slotName, url, highRequest);\r\n}\r\n\r\nvoid Utility::httpPost(QObject *caller, QByteArray slotName, QUrl url, QByteArray data, bool highRequest)\r\n{\r\n    http_request->post (caller, slotName, url, data, highRequest);\r\n}\r\n\r\nvoid Utility::socketAbort()\r\n{\r\n    http_request->abort ();\r\n}\r\n\r\nvoid Utility::setApplicationProxy(int type, QString location, QString port, QString username, QString password)\r\n{\r\n    QNetworkProxy proxy;\r\n    proxy.setType((QNetworkProxy::ProxyType)type);\r\n    proxy.setHostName(location);\r\n    proxy.setPort(port.toUShort ());\r\n    proxy.setUser (username);\r\n    proxy.setPassword (password);\r\n    QNetworkProxy::setApplicationProxy(proxy);\r\n}\r\n\r\nQString Utility::stringEncrypt(const QString &content, QString key)\r\n{\r\n    if(content==\"\"||key==\"\")\r\n        return content;\r\n    if(key.size ()>256)\r\n        key = key.mid (0,256);//密匙最长256位\r\n    QByteArray data = strZoarium (content.toUtf8 ().toBase64 ());\r\n    int data_size = data.size ();\r\n    QByteArray mykey = strZoarium (key.toLatin1 ().toHex ());\r\n    int key_size = mykey.size ();\r\n    //qDebug()<<data;\r\n    data=fillContent (data, 2*key_size-data_size);//填充字符串\r\n    //qDebug()<<data;\r\n    QByteArray temp=\"\";\r\n    for(int i=0;i<data.size ();++i){\r\n        int ch = (int)data[i]+(int)mykey[i%key_size];\r\n        //qDebug()<<ch<<(int)mykey[i%key_size]<<(int)data[i];\r\n        if(ch>=0)\r\n            temp.append (QString(ch));\r\n    }\r\n    //qDebug()<<temp;\r\n    return QString::fromUtf8 (temp);\r\n}\r\n\r\nQString Utility::stringUncrypt(const QString &content, QString key)\r\n{\r\n    if(content==\"\"||key==\"\")\r\n        return content;\r\n    if(key.size ()>256)\r\n        key = key.mid (0,256);//密匙最长256位\r\n    QByteArray data = content.toLatin1 ();\r\n    QByteArray mykey = strZoarium (key.toLatin1 ().toHex ());\r\n    int key_size = mykey.size ();\r\n    QByteArray temp;\r\n\r\n    for(int i=0;i<data.size ();++i){\r\n        int ch = (int)(uchar)data[i]-(int)mykey[i%key_size];\r\n        if(ch>=0){\r\n            temp.append ((char)ch);\r\n        }\r\n    }\r\n    temp = unStrZoarium (temp);\r\n    int fill_size = temp.mid (0, 3).toInt ();\r\n    temp = temp.mid (fill_size+3, temp.size ()-fill_size-3);//除去填充的字符\r\n    \r\n    return QString::fromUtf8 (QByteArray::fromBase64 (temp));\r\n}\r\n\r\nbool myRemovePath(QString dirPath, bool deleteHidden, bool deleteSelf)\r\n{\r\n    qDebug()<<\"removePath的进程\"<<QThread::currentThread ();\r\n    QDir entry (dirPath);\r\n    if(!entry.exists()||!entry.isReadable())\r\n        return false;\r\n    entry.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden);\r\n    QFileInfoList dirList = entry.entryInfoList();\r\n    bool bHaveHiddenFile = false;\r\n\r\n    if(!dirList.isEmpty()) {\r\n        for( int i = 0; i < dirList.size() ; ++i) {\r\n            QFileInfo info = dirList.at(i);\r\n            if(info.isHidden() && !deleteHidden) {\r\n                bHaveHiddenFile = true;\r\n                continue;\r\n            }\r\n            QString path = info.absoluteFilePath();\r\n            if(info.isDir()) {\r\n                if(!myRemovePath(path, deleteHidden, true))\r\n                    return false;\r\n            }else if(info.isFile()) {\r\n                if(!QFile::remove(path))\r\n                    return false;\r\n            }else\r\n                return false;\r\n        }\r\n    }\r\n\r\n    if(deleteSelf && !bHaveHiddenFile) {\r\n        if(!entry.rmdir(dirPath)) {\r\n            return false;\r\n        }\r\n    }\r\n    return true;\r\n}\r\n\r\nvoid Utility::removePath(QString dirPath, bool deleteHidden/*=false*/, bool deleteSelf/*=true*/)\r\n{\r\n    qDebug()<<\"removePath的调用进程\"<<QThread::currentThread ();\r\n    QtConcurrent::run(myRemovePath, dirPath, deleteHidden, deleteSelf);\r\n}\r\n"
  },
  {
    "path": "src/utility/utility.h",
    "content": "#ifndef UTILITY_H\r\n#define UTILITY_H\r\n\r\n#include <QObject>\r\n#include <QString>\r\n#include <QByteArray>\r\n#include <QTimer>\r\n#include <QPoint>\r\n#include <QSettings>\r\n#include <QNetworkConfigurationManager>\r\n#include <QQmlApplicationEngine>\r\n#include <QPointer>\r\n\r\nclass UtilityPrivate : public QObject\r\n{\r\n    Q_OBJECT\r\n    Q_ENUMS(ProxyType)\r\npublic:\r\n    enum ProxyType {\r\n        DefaultProxy,\r\n        Socks5Proxy,\r\n        NoProxy,\r\n        HttpProxy,\r\n        HttpCachingProxy,\r\n        FtpCachingProxy\r\n    };\r\n};\r\n\r\nclass MyHttpRequest;\r\nclass DownloadImage;\r\nclass Utility : public QObject\r\n{\r\n    Q_OBJECT\r\npublic:\r\n    static Utility *createUtilityClass();\r\n    \r\nprivate:\r\n    explicit Utility(QObject *parent = 0);\r\n    ~Utility();\r\n    QPointer<QQmlApplicationEngine> engine;\r\n    QPointer<QSettings> mysettings;\r\n    \r\n    MyHttpRequest *http_request;\r\n    DownloadImage *download_image;\r\n\r\n    QNetworkConfigurationManager networkConfigurationManager;\r\n    \r\n    char numToStr(int num);//将数字按一定的规律换算成字母\r\n    QByteArray strZoarium(const QByteArray &str);//按一定的规律加密字符串(只包含数字和字母的字符串)\r\n    QByteArray unStrZoarium(const QByteArray &str);//按一定的规律解密字符串(只包含数字和字母的字符串)\r\n    QByteArray fillContent(const QByteArray &str, int length);//将字符串填充到一定的长度\r\n\r\npublic:\r\n    Q_INVOKABLE void consoleLog(QString str);//输出调试信息\r\n    Q_INVOKABLE QString getCookie( QString cookieName );\r\n    QQmlApplicationEngine *qmlEngine();\r\n    MyHttpRequest *getHttpRequest();\r\n    DownloadImage *getDownloadImage();\r\n    bool networkIsOnline() const;\r\nsignals:\r\n    void mouseDesktopPosChanged(QPoint arg);\r\n    void networkOnlineStateChanged(bool isOnline);\r\npublic slots:\r\n    void initUtility(QSettings *settings=0, QQmlApplicationEngine *qmlEngine=0);\r\n    void setQmlEngine( QQmlApplicationEngine *new_engine );\r\n    QPoint mouseDesktopPos();\r\n    \r\n    void setQSettings(QSettings *settings);\r\n    void setValue( const QString & key, const QVariant & value);\r\n    QVariant value(const QString & key, const QVariant & defaultValue = QVariant()) const;\r\n    void removeValue( const QString & key );\r\n    \r\n    void loadQml( QUrl url );\r\n#if(QT_VERSION>=0x050000)\r\n    void downloadImage( QJSValue callbackFun, QUrl url, QString savePath, QString saveName );\r\n    void httpGet(QJSValue callbackFun, QUrl url, bool highRequest=false );\r\n    void httpPost(QJSValue callbackFun, QUrl url, QByteArray data=\"\", bool highRequest=false );\r\n#else\r\n    void downloadImage( QScriptValue callbackFun, QUrl url, QString savePath, QString saveName );\r\n    void httpGet(QScriptValue callbackFun, QUrl url, bool highRequest=false );\r\n    void httpPost(QScriptValue callbackFun, QUrl url, QByteArray data=\"\", bool highRequest=false );\r\n#endif\r\n    void downloadImage( QObject *caller, QByteArray slotName, QUrl url, QString savePath, QString saveName );\r\n    void httpGet(QObject *caller, QByteArray slotName, QUrl url, bool highRequest=false);\r\n    void httpPost(QObject *caller, QByteArray slotName, QUrl url, QByteArray data, bool highRequest=false);\r\n    void socketAbort();\r\n    void setApplicationProxy( int type, QString location, QString port, QString username, QString password );\r\n    \r\n    QString stringEncrypt(const QString &content, QString key);//加密任意字符串，中文请使用utf-8编码\r\n    QString stringUncrypt(const QString &content_hex, QString key);//解密加密后的字符串\r\n    \r\n    void removePath(QString dirPath ,bool deleteHidden = true, bool deleteSelf = true );\r\n};\r\n\r\n#endif // UTILITY_H\r\n"
  },
  {
    "path": "style/menuStyle.css",
    "content": "    QMenu::item:selected {\r\n         background: #F07000;\r\n         color:#E6FFFF;\r\n         height:25px;\r\n     }\r\n     QMenu{\r\n        background-image: url(\":/images/menu_background.png\");\r\n     }\r\n     QMenu::item{\r\n        padding-left:35px;\r\n        padding-right:30px;\r\n        height:22px;\r\n     }\r\n     QMenu::icon{\r\n        padding-left:8px;\r\n     }\r\n     QMenu::separator {\r\n          height: 1px;\r\n          margin:5px 0px 5px 22px;\r\n          background: #B2C0CD;\r\n     }\r\n"
  },
  {
    "path": "style/messageBoxStyle.css",
    "content": "QMessageBox{\r\n    background-image: url(\":/images/menu_background.png\");\r\n}\r\nQPushButton {\r\n    background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #ddd,stop: 1 #ccc);\r\n    border-radius: 10px;\r\n    padding: 6px;\r\n    min-width: 5em;\r\n}\r\nQPushButton::hover{\r\n    background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #ccc,stop: 1 #eee);\r\n}\r\nQPushButton::pressed{\r\n    background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #ccc,stop: 1 #bbb);\r\n}\r\n"
  },
  {
    "path": "style.qrc",
    "content": "<RCC>\r\n    <qresource prefix=\"/\">\r\n        <file>style/menuStyle.css</file>\r\n        <file>style/messageBoxStyle.css</file>\r\n    </qresource>\r\n</RCC>\r\n"
  }
]