📄 queueframe.cpp
字号:
/*
* Copyright (C) 2001-2003 Jacek Sieka, j_s@telia.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "stdafx.h"
#include "../client/DCPlusPlus.h"
#include "Resource.h"
#include "QueueFrame.h"
#include "SearchFrm.h"
#include "PrivateFrame.h"
#include "../client/SimpleXML.h"
#include "../client/StringTokenizer.h"
#include "../client/ShareManager.h"
QueueFrame* QueueFrame::frame = NULL;
#define FILE_LIST_NAME "File Lists"
int QueueFrame::columnIndexes[] = { COLUMN_TARGET, COLUMN_STATUS, COLUMN_SIZE, COLUMN_PRIORITY,
COLUMN_USERS, COLUMN_PATH, COLUMN_ERRORS };
int QueueFrame::columnSizes[] = { 200, 300, 75, 75, 200, 200, 200 };
static ResourceManager::Strings columnNames[] = { ResourceManager::FILENAME, ResourceManager::STATUS, ResourceManager::SIZE,
ResourceManager::PRIORITY, ResourceManager::USERS, ResourceManager::PATH, ResourceManager::ERRORS };
LRESULT QueueFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
dcassert(frame == NULL);
frame = this;
showTree = BOOLSETTING(QUEUEFRAME_SHOW_TREE);
CreateSimpleStatusBar(ATL_IDS_IDLEMESSAGE, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP);
ctrlStatus.Attach(m_hWndStatusBar);
ctrlQueue.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
WS_HSCROLL | WS_VSCROLL | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS, WS_EX_CLIENTEDGE, IDC_QUEUE);
if(BOOLSETTING(FULL_ROW_SELECT)) {
ctrlQueue.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
}
else {
ctrlQueue.SetExtendedListViewStyle(LVS_EX_HEADERDRAGDROP);
}
ctrlDirs.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES | TVS_SHOWSELALWAYS | TVS_DISABLEDRAGDROP,
WS_EX_CLIENTEDGE, IDC_DIRECTORIES);
ctrlDirs.SetImageList(WinUtil::fileImages, TVSIL_NORMAL);
ctrlQueue.SetImageList(WinUtil::fileImages, LVSIL_SMALL);
m_nProportionalPos = 2500;
SetSplitterPanes(ctrlDirs.m_hWnd, ctrlQueue.m_hWnd);
// Create listview columns
WinUtil::splitTokens(columnIndexes, SETTING(QUEUEFRAME_ORDER), COLUMN_LAST);
WinUtil::splitTokens(columnSizes, SETTING(QUEUEFRAME_WIDTHS), COLUMN_LAST);
for(int j=0; j<COLUMN_LAST; j++) {
int fmt = (j == COLUMN_SIZE) ? LVCFMT_RIGHT : LVCFMT_LEFT;
ctrlQueue.InsertColumn(j, CSTRING_I(columnNames[j]), fmt, columnSizes[j], j);
}
ctrlQueue.SetColumnOrderArray(COLUMN_LAST, columnIndexes);
ctrlQueue.SetBkColor(WinUtil::bgColor);
ctrlQueue.SetTextBkColor(WinUtil::bgColor);
ctrlQueue.SetTextColor(WinUtil::textColor);
ctrlDirs.SetBkColor(WinUtil::bgColor);
ctrlDirs.SetTextColor(WinUtil::textColor);
ctrlShowTree.Create(ctrlStatus.m_hWnd, rcDefault, "+/-", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
ctrlShowTree.SetButtonStyle(BS_AUTOCHECKBOX, false);
ctrlShowTree.SetCheck(showTree);
showTreeContainer.SubclassWindow(ctrlShowTree.m_hWnd);
singleMenu.CreatePopupMenu();
multiMenu.CreatePopupMenu();
browseMenu.CreatePopupMenu();
removeMenu.CreatePopupMenu();
pmMenu.CreatePopupMenu();
priorityMenu.CreatePopupMenu();
dirMenu.CreatePopupMenu();
readdMenu.CreatePopupMenu();
singleMenu.AppendMenu(MF_STRING, IDC_SEARCH_ALTERNATES, CSTRING(SEARCH_FOR_ALTERNATES));
singleMenu.AppendMenu(MF_STRING, IDC_MOVE, CSTRING(MOVE));
singleMenu.AppendMenu(MF_POPUP, (UINT)(HMENU)priorityMenu, CSTRING(SET_PRIORITY));
singleMenu.AppendMenu(MF_POPUP, (UINT)(HMENU)browseMenu, CSTRING(GET_FILE_LIST));
singleMenu.AppendMenu(MF_POPUP, (UINT)(HMENU)pmMenu, CSTRING(SEND_PRIVATE_MESSAGE));
singleMenu.AppendMenu(MF_POPUP, (UINT)(HMENU)readdMenu, CSTRING(READD_SOURCE));
singleMenu.AppendMenu(MF_SEPARATOR, 0, (LPCTSTR)NULL);
singleMenu.AppendMenu(MF_POPUP, (UINT)(HMENU)removeMenu, CSTRING(REMOVE_SOURCE));
singleMenu.AppendMenu(MF_STRING, IDC_REMOVE, CSTRING(REMOVE));
multiMenu.AppendMenu(MF_POPUP, (UINT)(HMENU)priorityMenu, CSTRING(SET_PRIORITY));
multiMenu.AppendMenu(MF_STRING, IDC_MOVE, CSTRING(MOVE));
multiMenu.AppendMenu(MF_SEPARATOR, 0, (LPCTSTR)NULL);
multiMenu.AppendMenu(MF_STRING, IDC_REMOVE, CSTRING(REMOVE));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_PAUSED, CSTRING(PAUSED));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_LOWEST, CSTRING(LOWEST));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_LOW, CSTRING(LOW));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_NORMAL, CSTRING(NORMAL));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_HIGH, CSTRING(HIGH));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_HIGHEST, CSTRING(HIGHEST));
dirMenu.AppendMenu(MF_POPUP, (UINT)(HMENU)priorityMenu, CSTRING(SET_PRIORITY));
dirMenu.AppendMenu(MF_STRING, IDC_MOVE, CSTRING(MOVE));
dirMenu.AppendMenu(MF_SEPARATOR, 0, (LPCTSTR)NULL);
dirMenu.AppendMenu(MF_STRING, IDC_REMOVE, CSTRING(REMOVE));
SetWindowText(CSTRING(DOWNLOAD_QUEUE));
addQueueList(QueueManager::getInstance()->lockQueue());
QueueManager::getInstance()->unlockQueue();
QueueManager::getInstance()->addListener(this);
memset(statusSizes, 0, sizeof(statusSizes));
statusSizes[0] = 16;
ctrlStatus.SetParts(6, statusSizes);
updateStatus();
bHandled = FALSE;
return 1;
}
QueueFrame::StringListInfo::StringListInfo(QueueItem* qi) {
columns[COLUMN_TARGET] = qi->getTargetFileName();
columns[COLUMN_SIZE] = (qi->getSize() == -1) ? STRING(UNKNOWN) : Util::formatBytes(qi->getSize());
string tmp;
int online = 0;
QueueItem::Source::Iter j;
for(j = qi->getSources().begin(); j != qi->getSources().end(); ++j) {
if(tmp.size() > 0)
tmp += ", ";
QueueItem::Source::Ptr sr = *j;
if(sr->getUser()->isOnline())
online++;
tmp += sr->getUser()->getFullNick();
}
columns[COLUMN_USERS] = tmp.empty() ? STRING(NO_USERS) : tmp;
tmp = Util::emptyString;
for(j = qi->getBadSources().begin(); j != qi->getBadSources().end(); ++j) {
QueueItem::Source::Ptr sr = *j;
if(!sr->isSet(QueueItem::Source::FLAG_REMOVED)) {
if(tmp.size() > 0)
tmp += ", ";
tmp += sr->getUser()->getNick();
tmp += " (";
if(sr->isSet(QueueItem::Source::FLAG_FILE_NOT_AVAILABLE)) {
tmp += STRING(FILE_NOT_AVAILABLE);
} else if(sr->isSet(QueueItem::Source::FLAG_PASSIVE)) {
tmp += STRING(PASSIVE_USER);
} else if(sr->isSet(QueueItem::Source::FLAG_ROLLBACK_INCONSISTENCY)) {
tmp += STRING(ROLLBACK_INCONSISTENCY);
} else if(sr->isSet(QueueItem::Source::FLAG_CRC_FAILED)) {
tmp += STRING(SFV_INCONSISTENCY);
}
tmp += ')';
}
}
columns[COLUMN_ERRORS] = tmp.empty() ? STRING(NO_ERRORS) : tmp;
if(qi->getStatus() == QueueItem::STATUS_WAITING) {
char buf[64];
if(online > 0) {
if(qi->getSources().size() == 1) {
columns[COLUMN_STATUS] = STRING(WAITING_USER_ONLINE);
} else {
sprintf(buf, CSTRING(WAITING_USERS_ONLINE), online, qi->getSources().size());
columns[COLUMN_STATUS] = buf;
}
} else {
if(qi->getSources().size() == 0) {
columns[COLUMN_STATUS] = STRING(NO_USERS_TO_DOWNLOAD_FROM);
} else if(qi->getSources().size() == 1) {
columns[COLUMN_STATUS] = STRING(USER_OFFLINE);
} else if(qi->getSources().size() == 2) {
columns[COLUMN_STATUS] = STRING(BOTH_USERS_OFFLINE);
} else if(qi->getSources().size() == 3) {
columns[COLUMN_STATUS] = STRING(ALL_3_USERS_OFFLINE);
} else if(qi->getSources().size() == 4) {
columns[COLUMN_STATUS] = STRING(ALL_4_USERS_OFFLINE);
} else {
sprintf(buf, CSTRING(ALL_USERS_OFFLINE), qi->getSources().size());
columns[COLUMN_STATUS] = buf;
}
}
} else if(qi->getStatus() == QueueItem::STATUS_RUNNING) {
columns[COLUMN_STATUS] = STRING(RUNNING);
}
switch(qi->getPriority()) {
case QueueItem::PAUSED: columns[COLUMN_PRIORITY] = STRING(PAUSED); break;
case QueueItem::LOWEST: columns[COLUMN_PRIORITY] = STRING(LOWEST); break;
case QueueItem::LOW: columns[COLUMN_PRIORITY] = STRING(LOW); break;
case QueueItem::NORMAL: columns[COLUMN_PRIORITY] = STRING(NORMAL); break;
case QueueItem::HIGH: columns[COLUMN_PRIORITY] = STRING(HIGH); break;
case QueueItem::HIGHEST: columns[COLUMN_PRIORITY] = STRING(HIGHEST); break;
default: dcassert(0); break;
}
columns[COLUMN_PATH] = qi->getTarget();
}
void QueueFrame::onQueueAdded(QueueItem* aQI) {
QueueItem* qi = new QueueItem(*aQI);
{
Lock l(cs);
dcassert(queue.find(aQI) == queue.end());
queue[aQI] = qi;
}
speak(ADD_ITEM, qi);
}
void QueueFrame::addQueueItem(QueueItem* qi) {
if(!qi->isSet(QueueItem::FLAG_USER_LIST)) {
queueSize+=qi->getSize();
}
queueItems++;
dirty = true;
string dir = Util::getFilePath(qi->getTarget());
bool updateDir = (directories.find(dir) == directories.end());
directories.insert(make_pair(dir, qi));
if(updateDir) {
addDirectory(dir, qi->isSet(QueueItem::FLAG_USER_LIST));
}
if(!showTree || (curDir == dir)) {
StringListInfo sli(qi);
StringList l;
for(int j = 0; j < COLUMN_LAST; j++) {
l.push_back(sli.columns[j]);
}
dcassert(ctrlQueue.find((LPARAM)qi) == -1);
ctrlQueue.insert(l, WinUtil::getIconIndex(qi->getTarget()), (LPARAM)qi);
}
}
void QueueFrame::addQueueList(const QueueItem::StringMap& li) {
ctrlQueue.SetRedraw(FALSE);
ctrlDirs.SetRedraw(FALSE);
for(QueueItem::StringMap::const_iterator j = li.begin(); j != li.end(); ++j) {
QueueItem* aQI = j->second;
QueueItem* qi = new QueueItem(*aQI);
dcassert(queue.find(aQI) == queue.end());
queue[aQI] = qi;
addQueueItem(qi);
}
ctrlQueue.SetRedraw(TRUE);
ctrlQueue.resort();
ctrlDirs.SetRedraw(TRUE);
ctrlDirs.Invalidate();
}
HTREEITEM QueueFrame::addDirectory(const string& dir, bool isFileList /* = false */) {
TVINSERTSTRUCT tvi;
tvi.hInsertAfter = TVI_SORT;
tvi.item.mask = TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT;
tvi.item.iImage = tvi.item.iSelectedImage = WinUtil::getDirIconIndex();
if(isFileList) {
// We assume we haven't added it yet, and that all filelists go to the same
// directory...
dcassert(fileLists == NULL);
tvi.hParent = NULL;
tvi.item.pszText = FILE_LIST_NAME;
tvi.item.lParam = (LPARAM) new string(dir);
fileLists = ctrlDirs.InsertItem(&tvi);
return fileLists;
}
// More complicated, we have to find the last available tree item and then see...
string::size_type i = 0;
string::size_type j;
HTREEITEM next = ctrlDirs.GetRootItem();
HTREEITEM parent = NULL;
if((next != NULL) && (next == fileLists)) {
next = ctrlDirs.GetNextSiblingItem(next);
}
if(next == NULL) {
// First addition, set commonStart to the dir minus the last part...
i = dir.rfind('\\', dir.length()-2);
if(i != string::npos) {
commonStart = dir.substr(0, i+1);
string name = commonStart.substr(0, commonStart.length() - 1);
tvi.hParent = NULL;
tvi.item.pszText = const_cast<char*>(name.c_str());
tvi.item.lParam = (LPARAM)new string(commonStart);
parent = ctrlDirs.InsertItem(&tvi);
next = NULL;
i++;
} else {
// No commonStart...
i = 0;
}
} else {
// Check if commonStart is the same as this dir start...
if(commonStart.empty()) {
// nothing...
} else if(Util::strnicmp(dir, commonStart, commonStart.length()) == 0) {
// Ok, np, commonstart is equal...
i = commonStart.length();
dcassert(next != NULL);
parent = next;
next = ctrlDirs.GetChildItem(next);
} else {
string oldCommon = commonStart;
i = 0;
for(;;) {
j = dir.find('\\', i);
if(j == string::npos) {
commonStart = dir.substr(0, i);
break;
}
if(Util::strnicmp(dir, commonStart, j) == 0) {
i = j + 1;
} else {
commonStart = dir.substr(0, i);
break;
}
}
if(commonStart.empty()) {
// We insert the first part, if not, addDirectory will return the old commonStart
// Since this gets sorted before oldCommon, it should work =)
i = oldCommon.find('\\');
dcassert(i != string::npos);
string* tmp = new string(oldCommon.substr(0, i+1));
string name = tmp->substr(0, tmp->length() - 1);
tvi.hParent = NULL;
tvi.item.pszText = const_cast<char*>(name.c_str());
tvi.item.lParam = (LPARAM)tmp;
ctrlDirs.InsertItem(&tvi);
HTREEITEM ht = addDirectory(oldCommon);
HTREEITEM ht2 = ctrlDirs.GetChildItem(next);
while(ht2 != NULL) {
moveNode(ht2, ht);
ht2 = ctrlDirs.GetChildItem(next);
}
delete (string*)ctrlDirs.GetItemData(next);
ctrlDirs.DeleteItem(next);
next = ctrlDirs.GetRootItem();
if((next != NULL) && (next == fileLists)) {
next = ctrlDirs.GetNextSiblingItem(next);
}
i = 0;
} else {
string name = commonStart.substr(0, commonStart.length() - 1);
tvi.hParent = NULL;
tvi.item.pszText = const_cast<char*>(name.c_str());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -