|
- #include "mainwindow.h"
- #include "ui_mainwindow.h"
- #include <thread>
- #include <QDir>
- #include <QDebug>
- #include <QMessageBox>
- #include <QTextCodec>
- #include <QFileDialog>
- #include <QDateTime>
- #include <QtMac>
- #include "addfellowdialog.h"
- #include <QProcess>
- #include "platformdepend.h"
- #include "feiqwin.h"
-
- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
- qRegisterMetaType<shared_ptr<ViewEvent>>("ViewEventSharedPtr");
-
- connect(this, SIGNAL(showErrorAndQuit(QString)), this, SLOT(onShowErrorAndQuit(QString)));
-
- //加载配置
- auto settingFilePath = QDir::home().filePath(".feiq_setting.ini");
- mSettings = new Settings(settingFilePath, QSettings::IniFormat);
- mSettings->setIniCodec(QTextCodec::codecForName("UTF-8"));
- mTitle = mSettings->value("app/title", "mac飞秋").toString();
- setWindowTitle(mTitle);
-
- //初始化搜索对话框
- mSearchFellowDlg = new SearchFellowDlg(this);
- connect(mSearchFellowDlg, SIGNAL(onFellowSelected(const Fellow*)),
- this, SLOT(finishSearch(const Fellow*)));
-
- connect(ui->actionRefreshFellows, SIGNAL(triggered(bool)), this, SLOT(refreshFellowList()));
- connect(ui->actionAddFellow, SIGNAL(triggered(bool)), this, SLOT(addFellow()));
-
- mSearchFellowDlg->setSearchDriver(std::bind(&MainWindow::fellowSearchDriver, this, placeholders::_1));
-
- //初始化文件管理对话框
- mDownloadFileDlg = new FileManagerDlg(this);
- mDownloadFileDlg->setEngine(&mFeiq);
- connect(this, SIGNAL(statChanged(FileTask*)), mDownloadFileDlg, SLOT(statChanged(FileTask*)));
- connect(this, SIGNAL(progressChanged(FileTask*)), mDownloadFileDlg, SLOT(progressChanged(FileTask*)));
-
- //初始化好友列表
- mFellowList.bindTo(ui->fellowListWidget);
- connect(&mFellowList, SIGNAL(select(const Fellow*)), this, SLOT(openChartTo(const Fellow*)));
-
- //初始化接收文本框
- mRecvTextEdit = ui->recvEdit;
- connect(mRecvTextEdit, SIGNAL(navigateToFileTask(IdType,IdType,bool)), this, SLOT(navigateToFileTask(IdType,IdType,bool)));
-
- //初始化发送文本框
- mSendTextEdit = ui->sendEdit;
- connect(mSendTextEdit, SIGNAL(acceptDropFiles(QList<QFileInfo>)), this, SLOT(sendFiles(QList<QFileInfo>)));
- if (mSettings->value("app/send_by_enter", true).toBool())
- {
- connect(mSendTextEdit, SIGNAL(enterPressed()), this, SLOT(sendText()));
- connect(mSendTextEdit, SIGNAL(ctrlEnterPressed()), mSendTextEdit, SLOT(newLine()));
- }
- else
- {
- connect(mSendTextEdit, SIGNAL(ctrlEnterPressed()), this, SLOT(sendText()));
- connect(mSendTextEdit, SIGNAL(enterPressed()), mSendTextEdit, SLOT(newLine()));
- }
-
- //初始化Emoji对话框
- mChooseEmojiDlg = new ChooseEmojiDlg(this);
- connect(ui->actionInsertEmoji, SIGNAL(triggered(bool)), this, SLOT(openChooseEmojiDlg()));
- connect(mChooseEmojiDlg, SIGNAL(choose(QString)),mSendTextEdit, SLOT(insertPlainText(QString)));
-
- //初始化菜单
- connect(ui->actionSearchFellow, SIGNAL(triggered(bool)), this, SLOT(openSearchDlg()));
- connect(ui->actionSettings, SIGNAL(triggered(bool)), this, SLOT(openSettings()));
- connect(ui->actionOpendl, SIGNAL(triggered(bool)), this, SLOT(openDownloadDlg()));
- connect(ui->actionSendText, SIGNAL(triggered(bool)), this, SLOT(sendText()));
- connect(ui->actionSendKnock, SIGNAL(triggered(bool)), this, SLOT(sendKnock()));
- connect(ui->actionSendFile, SIGNAL(triggered(bool)), this, SLOT(sendFile()));
-
- //初始化平台相关特性
- PlatformDepend::instance().setMainWnd(this);
-
- //初始化飞秋引擎
- connect(this, SIGNAL(feiqViewEvent(shared_ptr<ViewEvent>)), this, SLOT(handleFeiqViewEvent(shared_ptr<ViewEvent>)));
-
- //后台初始化通信
- std::thread thd(&MainWindow::initFeiq, this);
- thd.detach();
- }
-
- MainWindow::~MainWindow()
- {
- mFeiq.stop();
- mSettings->sync();
- delete mSettings;
- delete mSearchFellowDlg;
- delete mDownloadFileDlg;
- delete mChooseEmojiDlg;
- delete ui;
- }
-
- void MainWindow::setFeiqWin(FeiqWin *feiqWin)
- {
- mFeiqWin = feiqWin;
- mFeiqWin->init(this);
- }
-
- void MainWindow::onNotifyClicked(const QString& fellowIp)
- {
- qDebug()<<fellowIp;
- auto fellow = mFeiq.getModel().findFirstFellowOf(fellowIp.toStdString());
- if (fellow)
- openChartTo(fellow.get());
-
- raise();
- activateWindow();
- showNormal();
- }
-
- void MainWindow::onNotifyReplied(long notifyId, const QString &fellowIp, const QString &reply)
- {
- auto fellow = mFeiq.getModel().findFirstFellowOf(fellowIp.toStdString());
- if (fellow)
- {
- //回复消息
- auto content = make_shared<TextContent>();
- content->text = reply.toStdString();
-
- mFeiq.send(fellow, content);
-
- //设为已回复
- auto msgRepliedTo = findUnshownMessage(notifyId);
- if (msgRepliedTo)
- {
- msgRepliedTo->replied=true;
- }
-
- //将自己的回复放入未显示列表
- auto event = make_shared<MessageViewEvent>();
- event->contents.push_back(content);
- event->fellow = nullptr;
-
- auto& msg = addUnshownMessage(fellow.get(), event);
- msg.read = true;
-
- updateUnshownHint(fellow.get());
- }
- }
-
- void MainWindow::enterEvent(QEvent *event)
- {
- auto fellow = mRecvTextEdit->curFellow();
- if (fellow)
- {
- flushUnshown(fellow);
- updateUnshownHint(fellow);
- }
-
- PlatformDepend::instance().hideAllNotify();
- }
-
- void MainWindow::openChartTo(const Fellow *fellow)
- {
- mFellowList.top(*fellow);
- mRecvTextEdit->setCurFellow(fellow);
- setWindowTitle(mTitle + " - 与"+fellow->getName().c_str()+"会话中");
- flushUnshown(fellow);
- updateUnshownHint(fellow);
- }
-
- shared_ptr<Fellow> MainWindow::checkCurFellow()
- {
- auto fellow = mFeiq.getModel().getShared(mRecvTextEdit->curFellow());
- if (fellow == nullptr)
- {
- mRecvTextEdit->addWarning("这是要发给谁?");
- }
-
- return fellow;
- }
-
- void MainWindow::showResult(pair<bool, string> ret, const Content* content)
- {
- if (ret.first)
- mRecvTextEdit->addMyContent(content, QDateTime::currentDateTime().currentMSecsSinceEpoch());
- else
- mRecvTextEdit->addWarning(ret.second.c_str());
- }
-
- void MainWindow::onStateChanged(FileTask *fileTask)
- {
- if (fileTask->getState()==FileTaskState::Finish)
- {
- auto title = QString(fileTask->getTaskTypeDes().c_str())+"完成";
- PlatformDepend::instance().showNotify(title,
- fileTask->getContent()->filename.c_str(),
- fileTask->fellow()->getIp().c_str());
- }
- else if (fileTask->getState()==FileTaskState::Error)
- {
- auto title = QString(fileTask->getTaskTypeDes().c_str())+"失败";
- auto content = QString(fileTask->getContent()->filename.c_str());
- content += "\n";
- content += fileTask->getDetailInfo().c_str();
- PlatformDepend::instance().showNotify(title,
- content,
- fileTask->fellow()->getIp().c_str());
- }
-
- if (mDownloadFileDlg->isVisible())
- {
- emit statChanged(fileTask);
- }
- }
-
- void MainWindow::onProgress(FileTask *fileTask)
- {
- if (mDownloadFileDlg->isVisible())
- {
- emit progressChanged(fileTask);
- }
- }
-
- void MainWindow::onEvent(shared_ptr<ViewEvent> event)
- {
- emit feiqViewEvent(event);
- }
-
- void MainWindow::onShowErrorAndQuit(const QString &text)
- {
- QMessageBox::warning(this, "出错了,为什么?你猜!", text, "退出应用");
-
- QApplication::exit(-1);
- }
-
- void MainWindow::handleFeiqViewEvent(shared_ptr<ViewEvent> event)
- {
- if (event->what == ViewEventType::FELLOW_UPDATE)
- {
- auto e = static_cast<FellowViewEvent*>(event.get());
- mFellowList.update(*(e->fellow.get()));
- }
- else if (event->what == ViewEventType::SEND_TIMEO || event->what == ViewEventType::MESSAGE)
- {
- //地球人都知道这个分支中的ViewEvent继承自FellowViewEvent
- auto e = static_cast<FellowViewEvent*>(event.get());
- auto fellow = e->fellow.get();
-
- if (isActiveWindow() && fellow == mRecvTextEdit->curFellow())
- {//窗口可见,处理当前用户消息,其他用户消息则放入通知队列
- readEvent(event.get());
- }
- else
- {//窗口不可见,放入未读队列并通知
- auto& umsg = addUnshownMessage(fellow, event);
- notifyUnshown(umsg);
- updateUnshownHint(fellow);
- }
- }
- }
-
- void MainWindow::refreshFellowList()
- {
- mFeiq.sendImOnLine();
- }
-
- void MainWindow::addFellow()
- {
- AddFellowDialog dlg(this);
- if (dlg.exec() == QDialog::Accepted)
- {
- auto ip = dlg.getIp();
- userAddFellow(ip);
- }
- }
-
- void MainWindow::openChooseEmojiDlg()
- {
- mChooseEmojiDlg->exec();
- }
-
- void MainWindow::sendFiles(QList<QFileInfo> files)
- {
- auto fellow = checkCurFellow();
- if (!fellow)
- return;
-
- for (auto file : files)
- {
- if (file.isFile())
- {
- sendFile(file.absoluteFilePath().toStdString());
- }
- else
- {
- mRecvTextEdit->addWarning("不支持发送:"+file.absoluteFilePath());
- }
- }
- }
-
- void MainWindow::userAddFellow(QString ip)
- {
- //创建好友
- auto fellow = make_shared<Fellow>();
- fellow->setIp(ip.toStdString());
- fellow->setOnLine(true);
- mFeiq.getModel().addFellow(fellow);
-
- //添加到列表
- auto& ref = *(fellow.get());
- mFellowList.update(ref);
- mFellowList.top(ref);
-
- //发送在线
- mFeiq.sendImOnLine(fellow->getIp());
- }
-
- void MainWindow::notifyUnshown(UnshownMessage& umsg)
- {
- auto event = umsg.event.get();
- if (event->what == ViewEventType::SEND_TIMEO)
- {
- auto e = static_cast<const SendTimeoEvent*>(event);
- auto fellow = e->fellow.get();
- umsg.notifyId = showNotification(fellow, "发送超时:"+simpleTextOf(e->content.get()));
- }
- else if (event->what == ViewEventType::MESSAGE)
- {
- auto e = static_cast<const MessageViewEvent*>(event);
- auto fellow = e->fellow.get();
- QString text="";
- bool first=false;
- for (auto content : e->contents)
- {
- auto t = simpleTextOf(content.get());
- if (first)
- text = t;
- else
- text = text+"\n"+t;
- }
- umsg.notifyId = showNotification(fellow, text);
- }
- }
-
- long MainWindow::showNotification(const Fellow *fellow, const QString &text)
- {
- QString content(text);
- if (content.length()>100)
- content = content.left(100)+"...";
- return PlatformDepend::instance().showNotify(QString(fellow->getName().c_str())+":", content, fellow->getIp().c_str());
- }
-
- void MainWindow::navigateToFileTask(IdType packetNo, IdType fileId, bool upload)
- {
- auto task = mFeiq.getModel().findTask(packetNo, fileId, upload ? FileTaskType::Upload : FileTaskType::Download);
- openDownloadDlg();
- mDownloadFileDlg->select(task.get());
- }
-
- void MainWindow::sendFile(std::string filepath)
- {
- auto content = FileContent::createFileContentToSend(filepath);
- auto fellow = checkCurFellow();
- if (!fellow)
- return;
-
- if (content == nullptr)
- {
- mRecvTextEdit->addWarning("获取文件"+QString(filepath.c_str())+"的信息失败,不发送");
- }
- else
- {
- auto fileContent = shared_ptr<FileContent>(std::move(content));
- auto ret = mFeiq.send(fellow, fileContent);
- showResult(ret, fileContent.get());
- }
- }
-
- void MainWindow::sendFile()
- {
- auto fellow = checkCurFellow();
- if (!fellow)
- return;
-
- //文件多选
- QFileDialog fdlg(this, "选择要发送的文件");
- fdlg.setFileMode(QFileDialog::ExistingFiles);
- if (fdlg.exec() == QDialog::Accepted)
- {
- auto list = fdlg.selectedFiles();
- auto count = list.count();
- for (int i = 0; i < count; i++)
- {
- auto path = list.at(i);
- sendFile(path.toStdString());
- }
- }
- }
-
- void MainWindow::sendKnock()
- {
- auto fellow = checkCurFellow();
- if (fellow)
- {
- auto content = make_shared<KnockContent>();
- auto ret = mFeiq.send(fellow, content);
- showResult(ret, content.get());
- }
- }
-
- void MainWindow::sendText()
- {
- auto text = mSendTextEdit->toPlainText();
- if (text.isEmpty())
- {
- mRecvTextEdit->addWarning("发送空文本是不科学的,驳回");
- return;
- }
-
-
- auto fellow = checkCurFellow();
- if (fellow)
- {
- auto content = make_shared<TextContent>();
- content->text = text.toStdString();
- auto ret = mFeiq.send(fellow, content);
- showResult(ret, content.get());
- mSendTextEdit->clear();
- }
- }
-
- void MainWindow::finishSearch(const Fellow *fellow)
- {
- mFellowList.top(*fellow);
- openChartTo(fellow);
- }
-
- void MainWindow::openSettings()
- {
- QMessageBox::information(this, "设置", "设置文件在:"+mSettings->fileName()+"\n重启后生效",
- QMessageBox::Ok);
- }
-
- void MainWindow::openSearchDlg()
- {
- mSearchFellowDlg->exec();
- }
-
- void MainWindow::openDownloadDlg()
- {
- mDownloadFileDlg->show();
- mDownloadFileDlg->raise();
- }
-
- vector<const Fellow *> MainWindow::fellowSearchDriver(const QString &text)
- {
- auto fellows = mFeiq.getModel().searchFellow(text.toStdString());
- vector<const Fellow*> result;
- for (auto fellow : fellows)
- {
- result.push_back(fellow.get());
- }
- return result;
- }
-
- void MainWindow::initFeiq()
- {
- //配置飞秋
- auto name = mSettings->value("user/name").toString();
- if (name.isEmpty())
- {
- emit showErrorAndQuit("请先打开【"+mSettings->fileName()+"】设置用户名(user/name)");
- return;
- }
-
- mFeiq.setMyName(name.toStdString());
- mFeiq.setMyHost(mSettings->value("user/host","feiq by cy").toString().toStdString());
-
- auto customGrroup = mSettings->value("network/custom_group", "").toString();
- if (!customGrroup.isEmpty())
- {
- auto list = customGrroup.split("|");
- for (int i = 0; i < list.size(); i++)
- {
- QString ipPrefix = list[i];
- if (ipPrefix.endsWith("."))
- {
- for (int j = 2; j < 254; j++)
- {
- auto ip = ipPrefix+QString::number(j);
- mFeiq.addToBroadcast(ip.toStdString());
- }
- }
- }
- }
-
- mFeiq.setView(this);
-
- mFeiq.enableIntervalDetect(60);
-
- //启动飞秋
- auto ret = mFeiq.start();
- if (!ret.first)
- {
- emit showErrorAndQuit(ret.second.c_str());
- }
-
- qDebug()<<"feiq started";
- }
-
- void MainWindow::updateUnshownHint(const Fellow *fellow)
- {
- auto it = mUnshownEvents.find(fellow);
- if (it != mUnshownEvents.end())
- {
- auto count = it->second.size();
- if (count == 0)
- {
- mFellowList.mark(*fellow, "");
- }
- else
- {
- mFellowList.mark(*fellow, QString::number(count));
- }
- }
-
- setBadgeNumber(getUnreadCount());
- }
-
- int MainWindow::getUnreadCount()
- {
- auto begin = mUnshownEvents.begin();
- auto end = mUnshownEvents.end();
- auto count = 0;
- for (auto it = begin; it != end; it++)
- {
- for (auto msg : it->second)
- {
- if (msg.isUnread())
- ++count;
- }
- }
- return count;
- }
-
- void MainWindow::flushUnshown(const Fellow *fellow)
- {
- auto it = mUnshownEvents.find(fellow);
- if (it != mUnshownEvents.end())
- {
- auto& list = (*it).second;
- while (!list.empty())
- {
- auto msg = list.front();
- readEvent(msg.event.get());
- list.pop_front();
- }
- }
- }
-
- void MainWindow::readEvent(const ViewEvent *event)
- {
- if (event->what == ViewEventType::SEND_TIMEO)
- {
- auto e = static_cast<const SendTimeoEvent*>(event);
- auto simpleText = simpleTextOf(e->content.get());
- if (simpleText.length()>20){
- simpleText = simpleText.left(20)+"...";
- }
- mRecvTextEdit->addWarning("发送超时:"+simpleText);
- }
- else if (event->what == ViewEventType::MESSAGE)
- {
- auto e = static_cast<const MessageViewEvent*>(event);
- auto time = e->when.time_since_epoch().count();
- for (auto content : e->contents)
- {
- if (e->fellow == nullptr)
- mRecvTextEdit->addMyContent(content.get(), time);
- else
- mRecvTextEdit->addFellowContent(content.get(), time);
- }
- }
- }
-
- void MainWindow::setBadgeNumber(int number)
- {
- PlatformDepend::instance().setBadgeNumber(number);
- }
-
- QString MainWindow::simpleTextOf(const Content *content)
- {
- switch (content->type()) {
- case ContentType::Text:
- return static_cast<const TextContent*>(content)->text.c_str();
- break;
- case ContentType::File:
- return static_cast<const FileContent*>(content)->filename.c_str();
- case ContentType::Knock:
- return "窗口抖动";
- default:
- return "***";
- break;
- }
- }
-
- UnshownMessage &MainWindow::addUnshownMessage(const Fellow *fellow, shared_ptr<ViewEvent> event)
- {
- UnshownMessage msg;
- msg.event = event;
- mUnshownEvents[fellow].push_back(msg);
- return mUnshownEvents[fellow].back();
- }
-
- UnshownMessage* MainWindow::findUnshownMessage(int id)
- {
- auto begin = mUnshownEvents.begin();
- auto end = mUnshownEvents.end();
-
- for (auto it = begin; it != end; it++)
- {
- for (auto& msg : it->second){
- if (msg.notifyId == id)
- return &msg;
- }
- }
-
- return nullptr;
- }
|