You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

mainwindow.cpp 15 kB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include <thread>
  4. #include <QDir>
  5. #include <QDebug>
  6. #include <QMessageBox>
  7. #include <QTextCodec>
  8. #include <QFileDialog>
  9. #include <QDateTime>
  10. #include <QtMac>
  11. #include "addfellowdialog.h"
  12. #include <QProcess>
  13. #include "platformdepend.h"
  14. #include "feiqwin.h"
  15. MainWindow::MainWindow(QWidget *parent) :
  16. QMainWindow(parent),
  17. ui(new Ui::MainWindow)
  18. {
  19. ui->setupUi(this);
  20. qRegisterMetaType<shared_ptr<ViewEvent>>("ViewEventSharedPtr");
  21. connect(this, SIGNAL(showErrorAndQuit(QString)), this, SLOT(onShowErrorAndQuit(QString)));
  22. //加载配置
  23. auto settingFilePath = QDir::home().filePath(".feiq_setting.ini");
  24. mSettings = new Settings(settingFilePath, QSettings::IniFormat);
  25. mSettings->setIniCodec(QTextCodec::codecForName("UTF-8"));
  26. mTitle = mSettings->value("app/title", "mac飞秋").toString();
  27. setWindowTitle(mTitle);
  28. //初始化搜索对话框
  29. mSearchFellowDlg = new SearchFellowDlg(this);
  30. connect(mSearchFellowDlg, SIGNAL(onFellowSelected(const Fellow*)),
  31. this, SLOT(finishSearch(const Fellow*)));
  32. connect(ui->actionRefreshFellows, SIGNAL(triggered(bool)), this, SLOT(refreshFellowList()));
  33. connect(ui->actionAddFellow, SIGNAL(triggered(bool)), this, SLOT(addFellow()));
  34. mSearchFellowDlg->setSearchDriver(std::bind(&MainWindow::fellowSearchDriver, this, placeholders::_1));
  35. //初始化文件管理对话框
  36. mDownloadFileDlg = new FileManagerDlg(this);
  37. mDownloadFileDlg->setEngine(&mFeiq);
  38. connect(this, SIGNAL(statChanged(FileTask*)), mDownloadFileDlg, SLOT(statChanged(FileTask*)));
  39. connect(this, SIGNAL(progressChanged(FileTask*)), mDownloadFileDlg, SLOT(progressChanged(FileTask*)));
  40. //初始化好友列表
  41. mFellowList.bindTo(ui->fellowListWidget);
  42. connect(&mFellowList, SIGNAL(select(const Fellow*)), this, SLOT(openChartTo(const Fellow*)));
  43. //初始化接收文本框
  44. mRecvTextEdit = ui->recvEdit;
  45. connect(mRecvTextEdit, SIGNAL(navigateToFileTask(IdType,IdType,bool)), this, SLOT(navigateToFileTask(IdType,IdType,bool)));
  46. //初始化发送文本框
  47. mSendTextEdit = ui->sendEdit;
  48. connect(mSendTextEdit, SIGNAL(acceptDropFiles(QList<QFileInfo>)), this, SLOT(sendFiles(QList<QFileInfo>)));
  49. if (mSettings->value("app/send_by_enter", true).toBool())
  50. {
  51. connect(mSendTextEdit, SIGNAL(enterPressed()), this, SLOT(sendText()));
  52. connect(mSendTextEdit, SIGNAL(ctrlEnterPressed()), mSendTextEdit, SLOT(newLine()));
  53. }
  54. else
  55. {
  56. connect(mSendTextEdit, SIGNAL(ctrlEnterPressed()), this, SLOT(sendText()));
  57. connect(mSendTextEdit, SIGNAL(enterPressed()), mSendTextEdit, SLOT(newLine()));
  58. }
  59. //初始化Emoji对话框
  60. mChooseEmojiDlg = new ChooseEmojiDlg(this);
  61. connect(ui->actionInsertEmoji, SIGNAL(triggered(bool)), this, SLOT(openChooseEmojiDlg()));
  62. connect(mChooseEmojiDlg, SIGNAL(choose(QString)),mSendTextEdit, SLOT(insertPlainText(QString)));
  63. //初始化菜单
  64. connect(ui->actionSearchFellow, SIGNAL(triggered(bool)), this, SLOT(openSearchDlg()));
  65. connect(ui->actionSettings, SIGNAL(triggered(bool)), this, SLOT(openSettings()));
  66. connect(ui->actionOpendl, SIGNAL(triggered(bool)), this, SLOT(openDownloadDlg()));
  67. connect(ui->actionSendText, SIGNAL(triggered(bool)), this, SLOT(sendText()));
  68. connect(ui->actionSendKnock, SIGNAL(triggered(bool)), this, SLOT(sendKnock()));
  69. connect(ui->actionSendFile, SIGNAL(triggered(bool)), this, SLOT(sendFile()));
  70. //初始化飞秋引擎
  71. connect(this, SIGNAL(feiqViewEvent(shared_ptr<ViewEvent>)), this, SLOT(handleFeiqViewEvent(shared_ptr<ViewEvent>)));
  72. //后台初始化通信
  73. std::thread thd(&MainWindow::initFeiq, this);
  74. thd.detach();
  75. }
  76. MainWindow::~MainWindow()
  77. {
  78. mFeiq.stop();
  79. mSettings->sync();
  80. delete mSettings;
  81. delete mSearchFellowDlg;
  82. delete mDownloadFileDlg;
  83. delete mChooseEmojiDlg;
  84. delete ui;
  85. }
  86. void MainWindow::setFeiqWin(FeiqWin *feiqWin)
  87. {
  88. mFeiqWin = feiqWin;
  89. mFeiqWin->init(this);
  90. }
  91. void MainWindow::enterEvent(QEvent *event)
  92. {
  93. auto fellow = mRecvTextEdit->curFellow();
  94. if (fellow)
  95. {
  96. flushUnread(fellow);
  97. updateUnread(fellow);
  98. }
  99. PlatformDepend::instance().hideAllNotify();
  100. }
  101. void MainWindow::openChartTo(const Fellow *fellow)
  102. {
  103. mFellowList.top(*fellow);
  104. mRecvTextEdit->setCurFellow(fellow);
  105. setWindowTitle(mTitle + " - 与"+fellow->getName().c_str()+"会话中");
  106. flushUnread(fellow);
  107. updateUnread(fellow);
  108. }
  109. shared_ptr<Fellow> MainWindow::checkCurFellow()
  110. {
  111. auto fellow = mFeiq.getModel().getShared(mRecvTextEdit->curFellow());
  112. if (fellow == nullptr)
  113. {
  114. mRecvTextEdit->addWarning("这是要发给谁?");
  115. }
  116. return fellow;
  117. }
  118. void MainWindow::showResult(pair<bool, string> ret, const Content* content)
  119. {
  120. if (ret.first)
  121. mRecvTextEdit->addMyContent(content, QDateTime::currentDateTime().currentMSecsSinceEpoch());
  122. else
  123. mRecvTextEdit->addWarning(ret.second.c_str());
  124. }
  125. void MainWindow::onStateChanged(FileTask *fileTask)
  126. {
  127. if (mDownloadFileDlg->isVisible())
  128. {
  129. emit statChanged(fileTask);
  130. }
  131. }
  132. void MainWindow::onProgress(FileTask *fileTask)
  133. {
  134. if (mDownloadFileDlg->isVisible())
  135. {
  136. emit progressChanged(fileTask);
  137. }
  138. }
  139. void MainWindow::onEvent(shared_ptr<ViewEvent> event)
  140. {
  141. emit feiqViewEvent(event);
  142. }
  143. void MainWindow::onShowErrorAndQuit(const QString &text)
  144. {
  145. QMessageBox::warning(this, "出错了,为什么?你猜!", text, "退出应用");
  146. QApplication::exit(-1);
  147. }
  148. void MainWindow::handleFeiqViewEvent(shared_ptr<ViewEvent> event)
  149. {
  150. if (event->what == ViewEventType::FELLOW_UPDATE)
  151. {
  152. auto e = static_cast<FellowViewEvent*>(event.get());
  153. mFellowList.update(*(e->fellow.get()));
  154. }
  155. else if (event->what == ViewEventType::SEND_TIMEO || event->what == ViewEventType::MESSAGE)
  156. {
  157. //地球人都知道这个分支中的ViewEvent继承自FellowViewEvent
  158. auto e = static_cast<FellowViewEvent*>(event.get());
  159. auto fellow = e->fellow.get();
  160. if (isActiveWindow())
  161. {//窗口可见,处理当前用户消息,其他用户消息则放入通知队列
  162. if (fellow == mRecvTextEdit->curFellow())
  163. {
  164. readEvent(event.get());
  165. }
  166. else
  167. {
  168. mUnreadEvents[fellow].push_back(event);
  169. updateUnread(fellow);
  170. }
  171. }
  172. else
  173. {//窗口不可见,放入未读队列并通知
  174. mUnreadEvents[fellow].push_back(event);
  175. updateUnread(fellow);
  176. notifyUnread(event.get());
  177. }
  178. }
  179. }
  180. void MainWindow::refreshFellowList()
  181. {
  182. mFeiq.sendImOnLine();
  183. }
  184. void MainWindow::addFellow()
  185. {
  186. AddFellowDialog dlg(this);
  187. if (dlg.exec() == QDialog::Accepted)
  188. {
  189. auto ip = dlg.getIp();
  190. userAddFellow(ip);
  191. }
  192. }
  193. void MainWindow::openChooseEmojiDlg()
  194. {
  195. mChooseEmojiDlg->exec();
  196. }
  197. void MainWindow::sendFiles(QList<QFileInfo> files)
  198. {
  199. auto fellow = checkCurFellow();
  200. if (!fellow)
  201. return;
  202. for (auto file : files)
  203. {
  204. if (file.isFile())
  205. {
  206. sendFile(file.absoluteFilePath().toStdString());
  207. }
  208. else
  209. {
  210. mRecvTextEdit->addWarning("不支持发送:"+file.absoluteFilePath());
  211. }
  212. }
  213. }
  214. void MainWindow::userAddFellow(QString ip)
  215. {
  216. //创建好友
  217. auto fellow = make_shared<Fellow>();
  218. fellow->setIp(ip.toStdString());
  219. fellow->setOnLine(true);
  220. mFeiq.getModel().addFellow(fellow);
  221. //添加到列表
  222. auto& ref = *(fellow.get());
  223. mFellowList.update(ref);
  224. mFellowList.top(ref);
  225. //发送在线
  226. mFeiq.sendImOnLine(fellow->getIp());
  227. }
  228. void MainWindow::notifyUnread(const ViewEvent *event)
  229. {
  230. if (event->what == ViewEventType::SEND_TIMEO)
  231. {
  232. auto e = static_cast<const SendTimeoEvent*>(event);
  233. auto fellow = e->fellow.get();
  234. showNotification(fellow, "发送超时:"+simpleTextOf(e->content.get()));
  235. }
  236. else if (event->what == ViewEventType::MESSAGE)
  237. {
  238. auto e = static_cast<const MessageViewEvent*>(event);
  239. auto fellow = e->fellow.get();
  240. for (auto content : e->contents)
  241. {
  242. showNotification(fellow, simpleTextOf(content.get()));
  243. }
  244. }
  245. }
  246. void MainWindow::showNotification(const Fellow *fellow, const QString &text)
  247. {
  248. QString content(text);
  249. if (content.length()>20)
  250. content = content.left(20)+"...";
  251. PlatformDepend::instance().showNotify(QString(fellow->getName().c_str())+":", content);
  252. }
  253. void MainWindow::navigateToFileTask(IdType packetNo, IdType fileId, bool upload)
  254. {
  255. auto task = mFeiq.getModel().findTask(packetNo, fileId, upload ? FileTaskType::Upload : FileTaskType::Download);
  256. openDownloadDlg();
  257. mDownloadFileDlg->select(task.get());
  258. }
  259. void MainWindow::sendFile(std::string filepath)
  260. {
  261. auto content = FileContent::createFileContentToSend(filepath);
  262. auto fellow = checkCurFellow();
  263. if (!fellow)
  264. return;
  265. if (content == nullptr)
  266. {
  267. mRecvTextEdit->addWarning("获取文件"+QString(filepath.c_str())+"的信息失败,不发送");
  268. }
  269. else
  270. {
  271. auto fileContent = shared_ptr<FileContent>(std::move(content));
  272. auto ret = mFeiq.send(fellow, fileContent);
  273. showResult(ret, fileContent.get());
  274. }
  275. }
  276. void MainWindow::sendFile()
  277. {
  278. auto fellow = checkCurFellow();
  279. if (!fellow)
  280. return;
  281. //文件多选
  282. QFileDialog fdlg(this, "选择要发送的文件");
  283. fdlg.setFileMode(QFileDialog::ExistingFiles);
  284. if (fdlg.exec() == QDialog::Accepted)
  285. {
  286. auto list = fdlg.selectedFiles();
  287. auto count = list.count();
  288. for (int i = 0; i < count; i++)
  289. {
  290. auto path = list.at(i);
  291. sendFile(path.toStdString());
  292. }
  293. }
  294. }
  295. void MainWindow::sendKnock()
  296. {
  297. auto fellow = checkCurFellow();
  298. if (fellow)
  299. {
  300. auto content = make_shared<KnockContent>();
  301. auto ret = mFeiq.send(fellow, content);
  302. showResult(ret, content.get());
  303. }
  304. }
  305. void MainWindow::sendText()
  306. {
  307. auto text = mSendTextEdit->toPlainText();
  308. if (text.isEmpty())
  309. {
  310. mRecvTextEdit->addWarning("发送空文本是不科学的,驳回");
  311. return;
  312. }
  313. auto fellow = checkCurFellow();
  314. if (fellow)
  315. {
  316. auto content = make_shared<TextContent>();
  317. content->text = text.toStdString();
  318. auto ret = mFeiq.send(fellow, content);
  319. showResult(ret, content.get());
  320. mSendTextEdit->clear();
  321. }
  322. }
  323. void MainWindow::finishSearch(const Fellow *fellow)
  324. {
  325. mFellowList.top(*fellow);
  326. openChartTo(fellow);
  327. }
  328. void MainWindow::openSettings()
  329. {
  330. QMessageBox::information(this, "设置", "设置文件在:"+mSettings->fileName()+"\n重启后生效",
  331. QMessageBox::Ok);
  332. }
  333. void MainWindow::openSearchDlg()
  334. {
  335. mSearchFellowDlg->exec();
  336. }
  337. void MainWindow::openDownloadDlg()
  338. {
  339. mDownloadFileDlg->show();
  340. mDownloadFileDlg->raise();
  341. }
  342. vector<const Fellow *> MainWindow::fellowSearchDriver(const QString &text)
  343. {
  344. auto fellows = mFeiq.getModel().searchFellow(text.toStdString());
  345. vector<const Fellow*> result;
  346. for (auto fellow : fellows)
  347. {
  348. result.push_back(fellow.get());
  349. }
  350. return result;
  351. }
  352. void MainWindow::initFeiq()
  353. {
  354. //配置飞秋
  355. auto name = mSettings->value("user/name").toString();
  356. if (name.isEmpty())
  357. {
  358. emit showErrorAndQuit("请先打开【"+mSettings->fileName()+"】设置用户名(user/name)");
  359. return;
  360. }
  361. mFeiq.setMyName(name.toStdString());
  362. mFeiq.setMyHost(mSettings->value("user/host","feiq by cy").toString().toStdString());
  363. auto customGrroup = mSettings->value("network/custom_group", "").toString();
  364. if (!customGrroup.isEmpty())
  365. {
  366. auto list = customGrroup.split("|");
  367. for (int i = 0; i < list.size(); i++)
  368. {
  369. QString ipPrefix = list[i];
  370. if (ipPrefix.endsWith("."))
  371. {
  372. for (int j = 2; j < 254; j++)
  373. {
  374. auto ip = ipPrefix+QString::number(j);
  375. mFeiq.addToBroadcast(ip.toStdString());
  376. }
  377. }
  378. }
  379. }
  380. mFeiq.setView(this);
  381. mFeiq.enableIntervalDetect(60);
  382. //启动飞秋
  383. auto ret = mFeiq.start();
  384. if (!ret.first)
  385. {
  386. emit showErrorAndQuit(ret.second.c_str());
  387. }
  388. qDebug()<<"feiq started";
  389. }
  390. void MainWindow::updateUnread(const Fellow *fellow)
  391. {
  392. auto it = mUnreadEvents.find(fellow);
  393. if (it != mUnreadEvents.end())
  394. {
  395. auto count = (*it).second.size();
  396. if (count == 0)
  397. {
  398. mFellowList.mark(*fellow, "");
  399. }
  400. else
  401. {
  402. mFellowList.mark(*fellow, QString::number(count));
  403. }
  404. }
  405. setBadgeNumber(getUnreadCount());
  406. }
  407. int MainWindow::getUnreadCount()
  408. {
  409. auto begin = mUnreadEvents.begin();
  410. auto end = mUnreadEvents.end();
  411. auto count = 0;
  412. for (auto it = begin; it != end; it++)
  413. {
  414. count += it->second.size();
  415. }
  416. return count;
  417. }
  418. void MainWindow::flushUnread(const Fellow *fellow)
  419. {
  420. auto it = mUnreadEvents.find(fellow);
  421. if (it != mUnreadEvents.end())
  422. {
  423. auto& list = (*it).second;
  424. while (!list.empty())
  425. {
  426. auto event = list.front();
  427. readEvent(event.get());
  428. list.pop_front();
  429. }
  430. }
  431. }
  432. void MainWindow::readEvent(const ViewEvent *event)
  433. {
  434. if (event->what == ViewEventType::SEND_TIMEO)
  435. {
  436. auto e = static_cast<const SendTimeoEvent*>(event);
  437. auto simpleText = simpleTextOf(e->content.get());
  438. if (simpleText.length()>20){
  439. simpleText = simpleText.left(20)+"...";
  440. }
  441. mRecvTextEdit->addWarning("发送超时:"+simpleText);
  442. }
  443. else if (event->what == ViewEventType::MESSAGE)
  444. {
  445. auto e = static_cast<const MessageViewEvent*>(event);
  446. auto time = e->when.time_since_epoch().count();
  447. for (auto content : e->contents)
  448. {
  449. mRecvTextEdit->addFellowContent(content.get(), time);
  450. }
  451. }
  452. }
  453. void MainWindow::setBadgeNumber(int number)
  454. {
  455. PlatformDepend::instance().setBadgeNumber(number);
  456. }
  457. QString MainWindow::simpleTextOf(const Content *content)
  458. {
  459. switch (content->type()) {
  460. case ContentType::Text:
  461. return static_cast<const TextContent*>(content)->text.c_str();
  462. break;
  463. case ContentType::File:
  464. return static_cast<const FileContent*>(content)->filename.c_str();
  465. case ContentType::Knock:
  466. return "窗口抖动";
  467. default:
  468. return "***";
  469. break;
  470. }
  471. }

mac下的“飞秋”大多数只是飞鸽传书协议,而且未发现令人满意的开源项目,所以基于c++与qt实现了基础的飞秋协议。

Contributors (1)