📄 queueframe.cpp
字号:
/*
* Copyright (C) 2001-2006 Jacek Sieka, arnetheduck on gmail point 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 "LineDlg.h"
#include "../client/StringTokenizer.h"
#include "../client/ShareManager.h"
#include "../client/ClientManager.h"
#define FILE_LIST_NAME _T("File Lists")
int QueueFrame::columnIndexes[] = { COLUMN_TARGET, COLUMN_STATUS, COLUMN_SIZE, COLUMN_DOWNLOADED, COLUMN_PRIORITY,
COLUMN_USERS, COLUMN_PATH, COLUMN_EXACT_SIZE, COLUMN_ERRORS, COLUMN_ADDED, COLUMN_TTH, COLUMN_TYPE };
int QueueFrame::columnSizes[] = { 200, 300, 75, 110, 75, 200, 200, 75, 200, 100, 125, 75 };
static ResourceManager::Strings columnNames[] = { ResourceManager::FILENAME, ResourceManager::STATUS, ResourceManager::SIZE, ResourceManager::DOWNLOADED,
ResourceManager::PRIORITY, ResourceManager::USERS, ResourceManager::PATH, ResourceManager::EXACT_SIZE, ResourceManager::ERRORS,
ResourceManager::ADDED, ResourceManager::TTH_ROOT, ResourceManager::TYPE };
LRESULT QueueFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
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);
ctrlQueue.SetExtendedListViewStyle(LVS_EX_LABELTIP | LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT);
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 || j == COLUMN_DOWNLOADED || j == COLUMN_EXACT_SIZE) ? LVCFMT_RIGHT : LVCFMT_LEFT;
ctrlQueue.InsertColumn(j, CTSTRING_I(columnNames[j]), fmt, columnSizes[j], j);
}
ctrlQueue.SetColumnOrderArray(COLUMN_LAST, columnIndexes);
ctrlQueue.setSortColumn(COLUMN_TARGET);
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, _T("+/-"), 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();
removeAllMenu.CreatePopupMenu();
pmMenu.CreatePopupMenu();
priorityMenu.CreatePopupMenu();
dirMenu.CreatePopupMenu();
readdMenu.CreatePopupMenu();
singleMenu.AppendMenu(MF_STRING, IDC_SEARCH_ALTERNATES, CTSTRING(SEARCH_FOR_ALTERNATES));
singleMenu.AppendMenu(MF_STRING, IDC_BITZI_LOOKUP, CTSTRING(LOOKUP_AT_BITZI));
singleMenu.AppendMenu(MF_STRING, IDC_COPY_MAGNET, CTSTRING(COPY_MAGNET));
singleMenu.AppendMenu(MF_STRING, IDC_MOVE, CTSTRING(MOVE));
singleMenu.AppendMenu(MF_POPUP, (UINT_PTR)(HMENU)priorityMenu, CTSTRING(SET_PRIORITY));
singleMenu.AppendMenu(MF_POPUP, (UINT_PTR)(HMENU)browseMenu, CTSTRING(GET_FILE_LIST));
singleMenu.AppendMenu(MF_POPUP, (UINT_PTR)(HMENU)pmMenu, CTSTRING(SEND_PRIVATE_MESSAGE));
singleMenu.AppendMenu(MF_POPUP, (UINT_PTR)(HMENU)readdMenu, CTSTRING(READD_SOURCE));
singleMenu.AppendMenu(MF_SEPARATOR);
singleMenu.AppendMenu(MF_POPUP, (UINT_PTR)(HMENU)removeMenu, CTSTRING(REMOVE_SOURCE));
singleMenu.AppendMenu(MF_POPUP, (UINT_PTR)(HMENU)removeAllMenu, CTSTRING(REMOVE_FROM_ALL));
singleMenu.AppendMenu(MF_STRING, IDC_REMOVE, CTSTRING(REMOVE));
multiMenu.AppendMenu(MF_POPUP, (UINT_PTR)(HMENU)priorityMenu, CTSTRING(SET_PRIORITY));
multiMenu.AppendMenu(MF_STRING, IDC_MOVE, CTSTRING(MOVE));
multiMenu.AppendMenu(MF_SEPARATOR);
multiMenu.AppendMenu(MF_STRING, IDC_REMOVE, CTSTRING(REMOVE));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_PAUSED, CTSTRING(PAUSED));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_LOWEST, CTSTRING(LOWEST));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_LOW, CTSTRING(LOW));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_NORMAL, CTSTRING(NORMAL));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_HIGH, CTSTRING(HIGH));
priorityMenu.AppendMenu(MF_STRING, IDC_PRIORITY_HIGHEST, CTSTRING(HIGHEST));
dirMenu.AppendMenu(MF_POPUP, (UINT_PTR)(HMENU)priorityMenu, CTSTRING(SET_PRIORITY));
dirMenu.AppendMenu(MF_STRING, IDC_MOVE, CTSTRING(MOVE));
dirMenu.AppendMenu(MF_SEPARATOR);
dirMenu.AppendMenu(MF_STRING, IDC_REMOVE, CTSTRING(REMOVE));
removeMenu.AppendMenu(MF_STRING, IDC_REMOVE_SOURCES, CTSTRING(ALL));
removeMenu.AppendMenu(MF_SEPARATOR);
readdMenu.AppendMenu(MF_STRING, IDC_READD, CTSTRING(ALL));
readdMenu.AppendMenu(MF_SEPARATOR);
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;
}
void QueueFrame::QueueItemInfo::update() {
if(display != NULL) {
int colMask = updateMask;
updateMask = 0;
if(colMask & MASK_TARGET) {
display->columns[COLUMN_TARGET] = Util::getFileName(getTarget());
}
int online = 0;
if(colMask & MASK_USERS || colMask & MASK_STATUS) {
tstring tmp;
SourceIter j;
for(j = getSources().begin(); j != getSources().end(); ++j) {
if(tmp.size() > 0)
tmp += _T(", ");
if(j->getUser()->isOnline())
online++;
tmp += WinUtil::getNicks(j->getUser());
}
display->columns[COLUMN_USERS] = tmp.empty() ? TSTRING(NO_USERS) : tmp;
}
if(colMask & MASK_STATUS) {
if(getStatus() == QueueItem::STATUS_WAITING) {
TCHAR buf[64];
if(online > 0) {
if(getSources().size() == 1) {
display->columns[COLUMN_STATUS] = TSTRING(WAITING_USER_ONLINE);
} else {
_stprintf(buf, CTSTRING(WAITING_USERS_ONLINE), online, getSources().size());
display->columns[COLUMN_STATUS] = buf;
}
} else {
if(getSources().size() == 0) {
display->columns[COLUMN_STATUS] = TSTRING(NO_USERS_TO_DOWNLOAD_FROM);
} else if(getSources().size() == 1) {
display->columns[COLUMN_STATUS] = TSTRING(USER_OFFLINE);
} else if(getSources().size() == 2) {
display->columns[COLUMN_STATUS] = TSTRING(BOTH_USERS_OFFLINE);
} else if(getSources().size() == 3) {
display->columns[COLUMN_STATUS] = TSTRING(ALL_3_USERS_OFFLINE);
} else if(getSources().size() == 4) {
display->columns[COLUMN_STATUS] = TSTRING(ALL_4_USERS_OFFLINE);
} else {
_stprintf(buf, CTSTRING(ALL_USERS_OFFLINE), getSources().size());
display->columns[COLUMN_STATUS] = buf;
}
}
} else if(getStatus() == QueueItem::STATUS_RUNNING) {
display->columns[COLUMN_STATUS] = TSTRING(RUNNING);
}
}
if(colMask & MASK_SIZE) {
display->columns[COLUMN_SIZE] = (getSize() == -1) ? TSTRING(UNKNOWN) : Text::toT(Util::formatBytes(getSize()));
display->columns[COLUMN_EXACT_SIZE] = (getSize() == -1) ? TSTRING(UNKNOWN) : Text::toT(Util::formatExactSize(getSize()));
}
if(colMask & MASK_DOWNLOADED) {
if(getSize() > 0)
display->columns[COLUMN_DOWNLOADED] = Text::toT(Util::formatBytes(getDownloadedBytes()) + " (" + Util::toString((double)getDownloadedBytes()*100.0/(double)getSize()) + "%)");
else
display->columns[COLUMN_DOWNLOADED].clear();
}
if(colMask & MASK_PRIORITY) {
switch(getPriority()) {
case QueueItem::PAUSED: display->columns[COLUMN_PRIORITY] = TSTRING(PAUSED); break;
case QueueItem::LOWEST: display->columns[COLUMN_PRIORITY] = TSTRING(LOWEST); break;
case QueueItem::LOW: display->columns[COLUMN_PRIORITY] = TSTRING(LOW); break;
case QueueItem::NORMAL: display->columns[COLUMN_PRIORITY] = TSTRING(NORMAL); break;
case QueueItem::HIGH: display->columns[COLUMN_PRIORITY] = TSTRING(HIGH); break;
case QueueItem::HIGHEST: display->columns[COLUMN_PRIORITY] = TSTRING(HIGHEST); break;
default: dcasserta(0); break;
}
}
if(colMask & MASK_PATH) {
display->columns[COLUMN_PATH] = Util::getFilePath(getTarget());
}
if(colMask & MASK_ERRORS) {
tstring tmp;
SourceIter j;
for(j = getBadSources().begin(); j != getBadSources().end(); ++j) {
if(!j->isSet(QueueItem::Source::FLAG_REMOVED)) {
if(tmp.size() > 0)
tmp += _T(", ");
tmp += WinUtil::getNicks(j->getUser());
tmp += _T(" (");
if(j->isSet(QueueItem::Source::FLAG_FILE_NOT_AVAILABLE)) {
tmp += TSTRING(FILE_NOT_AVAILABLE);
} else if(j->isSet(QueueItem::Source::FLAG_PASSIVE)) {
tmp += TSTRING(PASSIVE_USER);
} else if(j->isSet(QueueItem::Source::FLAG_ROLLBACK_INCONSISTENCY)) {
tmp += TSTRING(ROLLBACK_INCONSISTENCY);
} else if(j->isSet(QueueItem::Source::FLAG_CRC_FAILED)) {
tmp += TSTRING(SFV_INCONSISTENCY);
} else if(j->isSet(QueueItem::Source::FLAG_BAD_TREE)) {
tmp += TSTRING(INVALID_TREE);
} else if(j->isSet(QueueItem::Source::FLAG_SLOW_SOURCE)) {
tmp += TSTRING(SOURCE_TOO_SLOW);
}
tmp += ')';
}
}
display->columns[COLUMN_ERRORS] = tmp.empty() ? TSTRING(NO_ERRORS) : tmp;
}
if(colMask & MASK_ADDED) {
display->columns[COLUMN_ADDED] = Text::toT(Util::formatTime("%Y-%m-%d %H:%M", getAdded()));
}
if(colMask & MASK_TTH && getTTH() != NULL) {
display->columns[COLUMN_TTH] = Text::toT(getTTH()->toBase32());
}
if(colMask & MASK_TYPE) {
display->columns[COLUMN_TYPE] = Util::getFileExt(getTarget());
if(display->columns[COLUMN_TYPE].size() > 0 && display->columns[COLUMN_TYPE][0] == '.')
display->columns[COLUMN_TYPE].erase(0, 1);
}
}
}
void QueueFrame::on(QueueManagerListener::Added, QueueItem* aQI) {
QueueItemInfo* ii = new QueueItemInfo(aQI);
{
Lock l(cs);
dcassert(queue.find(aQI) == queue.end());
queue[aQI] = ii;
}
speak(ADD_ITEM, ii);
}
void QueueFrame::addQueueItem(QueueItemInfo* ii, bool noSort) {
if(!ii->isSet(QueueItem::FLAG_USER_LIST)) {
queueSize+=ii->getSize();
}
queueItems++;
dirty = true;
const tstring& dir = ii->getPath();
bool updateDir = (directories.find(dir) == directories.end());
directories.insert(make_pair(dir, ii));
if(updateDir) {
addDirectory(dir, ii->isSet(QueueItem::FLAG_USER_LIST));
}
if(!showTree || isCurDir(dir)) {
ii->update();
if(noSort)
ctrlQueue.insertItem(ctrlQueue.GetItemCount(), ii, WinUtil::getIconIndex(ii->getTarget()));
else
ctrlQueue.insertItem(ii, WinUtil::getIconIndex(ii->getTarget()));
}
}
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;
QueueItemInfo* ii = new QueueItemInfo(aQI);
dcassert(queue.find(aQI) == queue.end());
queue[aQI] = ii;
addQueueItem(ii, true);
}
ctrlQueue.resort();
ctrlQueue.SetRedraw(TRUE);
ctrlDirs.SetRedraw(TRUE);
ctrlDirs.Invalidate();
}
LRESULT QueueFrame::onKeyDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) {
NMLVKEYDOWN* kd = (NMLVKEYDOWN*) pnmh;
if(kd->wVKey == VK_DELETE) {
removeSelected();
} else if(kd->wVKey == VK_ADD){
// Increase Item priority
changePriority(true);
} else if(kd->wVKey == VK_SUBTRACT){
// Decrease item priority
changePriority(false);
} else if(kd->wVKey == VK_TAB) {
onTab();
}
return 0;
}
HTREEITEM QueueFrame::addDirectory(const tstring& dir, bool isFileList /* = false */, HTREEITEM startAt /* = NULL */) {
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 tstring(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 = NULL;
HTREEITEM parent = NULL;
if(startAt == NULL) {
// First find the correct drive letter
dcassert(dir[1] == ':');
dcassert(dir[2] == '\\');
next = ctrlDirs.GetRootItem();
while(next != NULL) {
if(next != fileLists) {
tstring* stmp = (tstring*)ctrlDirs.GetItemData(next);
if(Util::strnicmp(*stmp, dir, 3) == 0)
break;
}
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 != tstring::npos) {
tstring name = dir.substr(0, i);
tvi.hParent = NULL;
tvi.item.pszText = const_cast<TCHAR*>(name.c_str());
tvi.item.lParam = (LPARAM)new tstring(dir.substr(0, i+1));
next = ctrlDirs.InsertItem(&tvi);
} else {
dcassert(dir.length() == 3);
tvi.hParent = NULL;
tvi.item.pszText = const_cast<TCHAR*>(dir.c_str());
tvi.item.lParam = (LPARAM)new tstring(dir);
next = ctrlDirs.InsertItem(&tvi);
}
}
// Ok, next now points to x:\... find how much is common
tstring* rootStr = (tstring*)ctrlDirs.GetItemData(next);
i = 0;
for(;;) {
j = dir.find('\\', i);
if(j == string::npos)
break;
if(Util::strnicmp(dir.c_str() + i, rootStr->c_str() + i, j - i + 1) != 0)
break;
i = j + 1;
}
if(i < rootStr->length()) {
HTREEITEM oldRoot = next;
// Create a new root
tstring name = rootStr->substr(0, i-1);
tvi.hParent = NULL;
tvi.item.pszText = const_cast<TCHAR*>(name.c_str());
tvi.item.lParam = (LPARAM)new tstring(rootStr->substr(0, i));
HTREEITEM newRoot = ctrlDirs.InsertItem(&tvi);
parent = addDirectory(*rootStr, false, newRoot);
next = ctrlDirs.GetChildItem(oldRoot);
while(next != NULL) {
moveNode(next, parent);
next = ctrlDirs.GetChildItem(oldRoot);
}
delete rootStr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -