Version: 0.1 / 5.40.2
This commit is contained in:
parent
e9d144b696
commit
e30709310e
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -2,6 +2,21 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [1.0.1 / 5.40.2] - 2020-06-01
|
||||
|
||||
### Added
|
||||
- Created a new Qt based UI names SandMan (Sandboxie Manager)
|
||||
- Resource monitor now shows the PID
|
||||
- Added basic API call log using updated BSA LogApiDll
|
||||
|
||||
|
||||
### Changed
|
||||
- reworked resource monitor to work with multiple event consumers
|
||||
- reworked log to work with multiple event consumers
|
||||
|
||||
|
||||
|
||||
## [5.40.1] - 2020-04-10
|
||||
|
||||
### Added
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28307.960
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SboxSvc", "core\svc\SboxSvc.vcxproj", "{2D3DBCAE-883E-54A6-F8F6-11228D989033}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
|
@ -69,7 +69,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SbieControl", "apps\control
|
|||
{8E0EAA5B-6F5B-E0E2-338A-453EF2B548E4} = {8E0EAA5B-6F5B-E0E2-338A-453EF2B548E4}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KmdUtil", "install\kmdutil\KmdUtil.vcxproj", "{0BF4988E-2325-4426-8CDC-BD221E4FB68C}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kmdutil", "install\kmdutil\KmdUtil.vcxproj", "{0BF4988E-2325-4426-8CDC-BD221E4FB68C}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{8E0EAA5B-6F5B-E0E2-338A-453EF2B548E4} = {8E0EAA5B-6F5B-E0E2-338A-453EF2B548E4}
|
||||
EndProjectSection
|
||||
|
@ -88,6 +88,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SboxHostDll", "SboxHostDll\
|
|||
{8E0EAA5B-6F5B-E0E2-338A-453EF2B548E4} = {8E0EAA5B-6F5B-E0E2-338A-453EF2B548E4}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{666D2193-3CF6-4358-8312-67A0C2B09E35}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\CHANGELOG.md = ..\CHANGELOG.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "com", "com", "{7495BFF6-A576-4B96-9071-10CF956368FC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{E9D1318A-FAF0-4EF8-8561-FCB03862AC99}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "apps", "apps", "{0301861F-98D8-4767-BA7D-E146DE2E0C92}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
SbieDebug|Win32 = SbieDebug|Win32
|
||||
|
@ -240,4 +251,23 @@ Global
|
|||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{2D3DBCAE-883E-54A6-F8F6-11228D989033} = {E9D1318A-FAF0-4EF8-8561-FCB03862AC99}
|
||||
{8B9E1B9D-FB3C-3009-9196-4315871BCD73} = {0301861F-98D8-4767-BA7D-E146DE2E0C92}
|
||||
{E40CC819-6990-DA28-3E1F-6708BC98E37B} = {7495BFF6-A576-4B96-9071-10CF956368FC}
|
||||
{8E0EAA5B-6F5B-E0E2-338A-453EF2B548E4} = {E9D1318A-FAF0-4EF8-8561-FCB03862AC99}
|
||||
{41453A79-CA9B-ABCA-981C-5242AFC72DDF} = {7495BFF6-A576-4B96-9071-10CF956368FC}
|
||||
{5410C534-4858-C748-86AD-0567A2451FDE} = {7495BFF6-A576-4B96-9071-10CF956368FC}
|
||||
{8055A629-631E-84F5-8F3C-1908F264C81D} = {7495BFF6-A576-4B96-9071-10CF956368FC}
|
||||
{42DB5510-0268-4655-B483-B9D6E4E48D62} = {7495BFF6-A576-4B96-9071-10CF956368FC}
|
||||
{255002EC-9FC7-422E-B497-BE2CC5012B2D} = {E9D1318A-FAF0-4EF8-8561-FCB03862AC99}
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288} = {E9D1318A-FAF0-4EF8-8561-FCB03862AC99}
|
||||
{D16E291A-1F8A-4B19-AE07-0AF8CB7CCBD0} = {0301861F-98D8-4767-BA7D-E146DE2E0C92}
|
||||
{0BF4988E-2325-4426-8CDC-BD221E4FB68C} = {0301861F-98D8-4767-BA7D-E146DE2E0C92}
|
||||
{B8D7002B-0468-44E7-93A7-94327A5D7C7A} = {0301861F-98D8-4767-BA7D-E146DE2E0C92}
|
||||
{3A42A9F3-E0C7-4633-9570-381802D6647D} = {E9D1318A-FAF0-4EF8-8561-FCB03862AC99}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8CC68B2E-A32E-409D-8D3F-F68AF524E29C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28307.1022
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SboxDrv", "core\drv\SboxDrv.vcxproj", "{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
|
@ -27,6 +27,14 @@ Global
|
|||
SbieRelease|x64 = SbieRelease|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.Debug|Win32.ActiveCfg = SbieDebug|Win32
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.Debug|Win32.Build.0 = SbieDebug|Win32
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.Debug|x64.ActiveCfg = SbieDebug|x64
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.Debug|x64.Build.0 = SbieDebug|x64
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.Release|Win32.ActiveCfg = SbieRelease|Win32
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.Release|Win32.Build.0 = SbieRelease|Win32
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.Release|x64.ActiveCfg = SbieRelease|x64
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.Release|x64.Build.0 = SbieRelease|x64
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.SbieDebug|Win32.ActiveCfg = SbieDebug|Win32
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.SbieDebug|Win32.Build.0 = SbieDebug|Win32
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.SbieDebug|x64.ActiveCfg = SbieDebug|x64
|
||||
|
@ -35,6 +43,14 @@ Global
|
|||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.SbieRelease|Win32.Build.0 = SbieRelease|Win32
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.SbieRelease|x64.ActiveCfg = SbieRelease|x64
|
||||
{4019C5EB-8D1E-40E4-B7D1-5601B4B27288}.SbieRelease|x64.Build.0 = SbieRelease|x64
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.Debug|Win32.ActiveCfg = SbieRelease|Win32
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.Debug|Win32.Build.0 = SbieRelease|Win32
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.Debug|x64.ActiveCfg = SbieRelease|x64
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.Debug|x64.Build.0 = SbieRelease|x64
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.Release|Win32.ActiveCfg = SbieRelease|Win32
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.Release|Win32.Build.0 = SbieRelease|Win32
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.Release|x64.ActiveCfg = SbieRelease|x64
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.Release|x64.Build.0 = SbieRelease|x64
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.SbieDebug|Win32.ActiveCfg = SbieRelease|Win32
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.SbieDebug|Win32.Build.0 = SbieRelease|Win32
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.SbieDebug|x64.ActiveCfg = SbieRelease|x64
|
||||
|
@ -43,6 +59,14 @@ Global
|
|||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.SbieRelease|Win32.Build.0 = SbieRelease|Win32
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.SbieRelease|x64.ActiveCfg = SbieRelease|x64
|
||||
{63B0DDD2-5E3B-EF38-F711-9652D2EB73B3}.SbieRelease|x64.Build.0 = SbieRelease|x64
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.Debug|Win32.ActiveCfg = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.Debug|Win32.Build.0 = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.Debug|x64.ActiveCfg = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.Debug|x64.Build.0 = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.Release|Win32.ActiveCfg = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.Release|Win32.Build.0 = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.Release|x64.ActiveCfg = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.Release|x64.Build.0 = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.SbieDebug|Win32.ActiveCfg = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.SbieDebug|Win32.Build.0 = SbieRelease|Win32
|
||||
{7BA01954-12F1-4CEE-BA97-FAD3250D9776}.SbieDebug|x64.ActiveCfg = SbieRelease|Win32
|
||||
|
@ -55,4 +79,7 @@ Global
|
|||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {806E7BFC-90B6-4D60-A232-3321EA1A60BA}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -94,6 +94,8 @@ CMessageDialog::CMessageDialog(CWnd *pParentWnd, int mode)
|
|||
m_buf_len = (8 * 1024);
|
||||
m_buf = malloc_WCHAR(m_buf_len);
|
||||
|
||||
m_last_message_number = 0;
|
||||
|
||||
if (mode == MSGDLG_NORMAL)
|
||||
ReloadConf();
|
||||
|
||||
|
@ -250,19 +252,23 @@ void CMessageDialog::OnTimer()
|
|||
while (1) {
|
||||
|
||||
ULONG len = m_buf_len;
|
||||
LONG status = SbieApi_GetWork(CMyApp::m_session_id, m_buf, &len);
|
||||
if (status != 0)
|
||||
break;
|
||||
ULONG message_number = m_last_message_number;
|
||||
ULONG code = -1;
|
||||
LONG status = SbieApi_GetMessage(&message_number, CMyApp::m_session_id, &code, m_buf, len);
|
||||
if (status != 0)
|
||||
break; // error or no more entries
|
||||
|
||||
ULONG *type = (ULONG *)m_buf;
|
||||
if (*type != API_LOG_MESSAGE)
|
||||
//if (message_number != m_last_message_number + 1)
|
||||
// we missed something
|
||||
m_last_message_number = message_number;
|
||||
|
||||
if (code == 0)
|
||||
continue; // empty dummy
|
||||
|
||||
if (/*code == MSG_2199 &&*/ m_firsttime)
|
||||
continue;
|
||||
|
||||
ULONG code = type[1];
|
||||
if (code == MSG_2199 && m_firsttime)
|
||||
continue;
|
||||
|
||||
WCHAR *str1 = (WCHAR *)&type[2];
|
||||
WCHAR *str1 = m_buf;
|
||||
ULONG str1_len = wcslen(str1);
|
||||
WCHAR *str2 = str1 + str1_len + 1;
|
||||
ULONG str2_len = wcslen(str2);
|
||||
|
|
|
@ -55,6 +55,8 @@ class CMessageDialog : public CBaseDialog
|
|||
|
||||
CPtrArray m_hidden;
|
||||
|
||||
ULONG m_last_message_number;
|
||||
|
||||
BOOL IsHiddenMessage(
|
||||
ULONG code, const WCHAR *detail_1, const WCHAR *detail_2);
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ CMonitorDialog::CMonitorDialog(CWnd *pParentWnd)
|
|||
m_username[0] = L'\0';
|
||||
m_username[255] = L'\0';
|
||||
m_username_len = wcslen(m_username);
|
||||
|
||||
m_last_entry_seq_num = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -105,15 +107,22 @@ void CMonitorDialog::OnIdle()
|
|||
static const WCHAR *_Separator = L" -------------------------------";
|
||||
|
||||
CListBox *listbox = (CListBox *)GetDlgItem(ID_MESSAGE_LIST);
|
||||
WCHAR name[280];
|
||||
WCHAR name[300];
|
||||
|
||||
while (1) {
|
||||
|
||||
ULONG seq_num = m_last_entry_seq_num;
|
||||
USHORT type;
|
||||
SbieApi_MonitorGet(&type, &name[12]);
|
||||
ULONG64 pid;
|
||||
SbieApi_MonitorGetEx(&seq_num, &type, &pid, &name[12]);
|
||||
if ((! type) || (! name[12]))
|
||||
break;
|
||||
|
||||
if(seq_num != m_last_entry_seq_num + 1)
|
||||
SbieApi_Log(MSG_1242, L"Resource access logger overflow!"); // MSG_MONITOR_OVERFLOW
|
||||
m_last_entry_seq_num = seq_num;
|
||||
|
||||
// privacy protection, hide username
|
||||
while (m_username_len) {
|
||||
WCHAR *username_ptr = wcsstr(&name[12], m_username);
|
||||
if (! username_ptr)
|
||||
|
@ -126,12 +135,11 @@ void CMonitorDialog::OnIdle()
|
|||
name[10] = L' ';
|
||||
name[9] = L' ';
|
||||
if (type & MONITOR_OPEN) {
|
||||
type &= ~MONITOR_OPEN;
|
||||
name[9] = L'O';
|
||||
} else if (type & MONITOR_DENY) {
|
||||
type &= ~MONITOR_DENY;
|
||||
name[9] = L'X';
|
||||
}
|
||||
type &= 0x0FFF;
|
||||
|
||||
const WCHAR *PrefixPtr = _Unknown;
|
||||
if (type == MONITOR_PIPE)
|
||||
|
@ -152,6 +160,8 @@ void CMonitorDialog::OnIdle()
|
|||
PrefixPtr = _Other;
|
||||
wcsncpy(name, PrefixPtr, 9);
|
||||
|
||||
wsprintf(&name[wcslen(name)], L"; PID: %I64u", pid);
|
||||
|
||||
int index = listbox->AddString(name);
|
||||
|
||||
WCHAR oldname[280];
|
||||
|
|
|
@ -30,6 +30,7 @@ class CMonitorDialog : public CBaseDialog
|
|||
|
||||
WCHAR m_username[256];
|
||||
ULONG m_username_len;
|
||||
ULONG m_last_entry_seq_num;
|
||||
|
||||
virtual BOOL OnInitDialog();
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#define MY_VERSION_BINARY 5,40
|
||||
#define MY_VERSION_STRING "5.40"
|
||||
#define MY_VERSION_STRING_EX "5.40.1"
|
||||
#define MY_VERSION_STRING_EX "5.40.2"
|
||||
|
||||
// These #defines are used by either Resource Compiler, or by NSIC installer
|
||||
#define SBIE_INSTALLER_PATH "..\\Bin\\"
|
||||
|
|
|
@ -218,7 +218,7 @@ typedef struct _OBJECT_BASIC_INFORMATION {
|
|||
} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
|
||||
|
||||
typedef struct _OBJECT_NAME_INFORMATION {
|
||||
UNICODE_STRING ObjectName;
|
||||
UNICODE_STRING Name;
|
||||
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
|
||||
|
||||
typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
|
||||
|
@ -921,6 +921,24 @@ typedef enum _PROCESSINFOCLASS {
|
|||
ProcessDebugObjectHandle, // 30
|
||||
ProcessDebugFlags,
|
||||
ProcessHandleTracing,
|
||||
ProcessIoPriority,
|
||||
ProcessExecuteFlags,
|
||||
ProcessResourceManagement, // ProcessTlsInformation
|
||||
ProcessCookie,
|
||||
ProcessImageInformation,
|
||||
ProcessCycleTime,
|
||||
ProcessPagePriority,
|
||||
ProcessInstrumentationCallback, // 40
|
||||
ProcessThreadStackAllocation,
|
||||
ProcessWorkingSetWatchEx,
|
||||
ProcessImageFileNameWin32,
|
||||
ProcessImageFileMapping,
|
||||
ProcessAffinityUpdateMode,
|
||||
ProcessMemoryAllocationMode,
|
||||
ProcessGroupInformation,
|
||||
ProcessTokenVirtualizationEnabled,
|
||||
ProcessConsoleHostProcess,
|
||||
ProcessWindowInformation, // 50
|
||||
MaxProcessInfoClass // MaxProcessInfoClass should always be the last enum
|
||||
} PROCESSINFOCLASS;
|
||||
|
||||
|
@ -931,7 +949,7 @@ typedef struct _PROCESS_BASIC_INFORMATION {
|
|||
LONG BasePriority; // was type KPRIORITY
|
||||
ULONG_PTR UniqueProcessId;
|
||||
ULONG_PTR InheritedFromUniqueProcessId;
|
||||
} PROCESS_BASIC_INFORMATION;
|
||||
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
|
||||
|
||||
typedef struct _PROCESS_IMAGE_FILE_NAME {
|
||||
USHORT Length;
|
||||
|
@ -1241,56 +1259,110 @@ typedef enum _SYSTEM_INFORMATION_CLASS {
|
|||
SystemProcessorInformation,
|
||||
SystemPerformanceInformation,
|
||||
SystemTimeOfDayInformation,
|
||||
SystemNotImplemented1,
|
||||
SystemPathInformation,
|
||||
SystemProcessInformation, // 5
|
||||
SystemCallCounts,
|
||||
SystemConfigurationInformation,
|
||||
SystemProcessorTimes,
|
||||
SystemGlobalFlag,
|
||||
SystemNotImplemented2, // 10
|
||||
SystemCallCountInformation,
|
||||
SystemDeviceInformation,
|
||||
SystemProcessorPerformanceInformation,
|
||||
SystemFlagsInformation,
|
||||
SystemCallTimeInformation, // 10
|
||||
SystemModuleInformation, // 11
|
||||
SystemLockInformation,
|
||||
SystemNotImplemented3,
|
||||
SystemNotImplemented4,
|
||||
SystemNotImplemented5,
|
||||
SystemLocksInformation,
|
||||
SystemStackTraceInformation,
|
||||
SystemPagedPoolInformation,
|
||||
SystemNonPagedPoolInformation,
|
||||
SystemHandleInformation,
|
||||
SystemObjectInformation,
|
||||
SystemPagefileInformation,
|
||||
SystemInstructionEmulationCounts,
|
||||
SystemInvalidInfoClass1,
|
||||
SystemCacheInformation,
|
||||
SystemPoolTagInformation,
|
||||
SystemProcessorStatistics,
|
||||
SystemDpcInformation,
|
||||
SystemNotImplemented6,
|
||||
SystemLoadImage,
|
||||
SystemUnloadImage,
|
||||
SystemTimeAdjustment,
|
||||
SystemNotImplemented7,
|
||||
SystemNotImplemented8,
|
||||
SystemNotImplemented9,
|
||||
SystemPageFileInformation,
|
||||
SystemVdmInstemulInformation,
|
||||
SystemVdmBopInformation,
|
||||
SystemFileCacheInformation,
|
||||
SystemPoolTagInformation,
|
||||
SystemInterruptInformation,
|
||||
SystemDpcBehaviorInformation,
|
||||
SystemFullMemoryInformation,
|
||||
SystemLoadGdiDriverInformation,
|
||||
SystemUnloadGdiDriverInformation,
|
||||
SystemTimeAdjustmentInformation,
|
||||
SystemSummaryMemoryInformation,
|
||||
SystemMirrorMemoryInformation,
|
||||
SystemPerformanceTraceInformation,
|
||||
SystemCrashDumpInformation,
|
||||
SystemExceptionInformation, // 33
|
||||
SystemCrashDumpStateInformation,
|
||||
SystemKernelDebuggerInformation,
|
||||
SystemContextSwitchInformation,
|
||||
SystemRegistryQuotaInformation, // 37
|
||||
SystemLoadAndCallImage,
|
||||
SystemPrioritySeparation,
|
||||
SystemNotImplemented10,
|
||||
SystemNotImplemented11,
|
||||
SystemInvalidInfoClass2,
|
||||
SystemInvalidInfoClass3,
|
||||
SystemTimeZoneInformation,
|
||||
SystemExtendServiceTableInformation,
|
||||
SystemPrioritySeperation,
|
||||
SystemVerifierAddDriverInformation,
|
||||
SystemVerifierRemoveDriverInformation,
|
||||
SystemProcessorIdleInformation,
|
||||
SystemLegacyDriverInformation,
|
||||
SystemCurrentTimeZoneInformation,
|
||||
SystemLookasideInformation, // 45
|
||||
SystemSetTimeSlipEvent,
|
||||
SystemTimeSlipNotification,
|
||||
SystemSessionCreate,
|
||||
SystemSessionDetach,
|
||||
SystemInvalidInfoClass4,
|
||||
SystemSessionInformation,
|
||||
SystemRangeStartInformation, // 50
|
||||
SystemVerifierInformation,
|
||||
SystemAddVerifier,
|
||||
SystemSessionProcessesInformation
|
||||
SystemVerifierThunkExtend,
|
||||
SystemSessionProcessInformation,
|
||||
SystemLoadGdiDriverInSystemSpace,
|
||||
SystemNumaProcessorMap,
|
||||
SystemPrefetcherInformation,
|
||||
SystemExtendedProcessInformation,
|
||||
SystemRecommendedSharedDataAlignment,
|
||||
SystemComPlusPackage,
|
||||
SystemNumaAvailableMemory,
|
||||
SystemProcessorPowerInformation,
|
||||
SystemEmulationBasicInformation, // WOW64
|
||||
SystemEmulationProcessorInformation, // WOW64
|
||||
SystemExtendedHandleInformation,
|
||||
SystemLostDelayedWriteInformation,
|
||||
SystemBigPoolInformation,
|
||||
SystemSessionPoolTagInformation,
|
||||
SystemSessionMappedViewInformation,
|
||||
SystemHotpatchInformation,
|
||||
SystemObjectSecurityMode,
|
||||
SystemWatchdogTimerHandler,
|
||||
SystemWatchdogTimerInformation,
|
||||
SystemLogicalProcessorInformation,
|
||||
SystemWow64SharedInformationObsolete,
|
||||
SystemRegisterFirmwareTableInformationHandler,
|
||||
SystemFirmwareTableInformation,
|
||||
SystemModuleInformationEx,
|
||||
SystemVerifierTriageInformation,
|
||||
SystemSuperfetchInformation,
|
||||
SystemMemoryListInformation,
|
||||
SystemFileCacheInformationEx,
|
||||
SystemThreadPriorityClientIdInformation,
|
||||
SystemProcessorIdleCycleTimeInformation,
|
||||
SystemVerifierCancellationInformation,
|
||||
SystemProcessorPowerInformationEx,
|
||||
SystemRefTraceInformation,
|
||||
SystemSpecialPoolInformation,
|
||||
SystemProcessIdInformation,
|
||||
SystemErrorPortInformation,
|
||||
SystemBootEnvironmentInformation,
|
||||
SystemHypervisorInformation,
|
||||
SystemVerifierInformationEx,
|
||||
SystemTimeZoneInformation,
|
||||
SystemImageFileExecutionOptionsInformation,
|
||||
SystemCoverageInformation,
|
||||
SystemPrefetchPatchInformation,
|
||||
SystemVerifierFaultsInformation,
|
||||
SystemSystemPartitionInformation,
|
||||
SystemSystemDiskInformation,
|
||||
SystemProcessorPerformanceDistribution,
|
||||
SystemNumaProximityNodeInformation,
|
||||
SystemDynamicTimeZoneInformation,
|
||||
SystemCodeIntegrityInformation,
|
||||
SystemProcessorMicrocodeUpdateInformation,
|
||||
SystemProcessorBrandString,
|
||||
SystemVirtualAddressInformation,
|
||||
MaxSystemInfoClass
|
||||
} SYSTEM_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _MODULE_INFO {
|
||||
|
@ -1711,10 +1783,11 @@ __declspec(dllimport) NTSTATUS NtUnloadDriver(
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
typedef enum _MEMORY_INFORMATION_CLASS {
|
||||
MemoryBasicInformation,
|
||||
MemoryWorkingSetList,
|
||||
MemorySectionName,
|
||||
MemoryBasicVlmInformation
|
||||
MemoryBasicInformation,
|
||||
MemoryWorkingSetInformation,
|
||||
MemoryMappedFilenameInformation,
|
||||
MemoryRegionInformation,
|
||||
MemoryWorkingSetExInformation
|
||||
} MEMORY_INFORMATION_CLASS;
|
||||
|
||||
__declspec(dllimport) NTSTATUS NtAllocateVirtualMemory(
|
||||
|
|
|
@ -26,7 +26,8 @@ SbieApi_GetFileName=_SbieApi_GetFileName@12
|
|||
SbieApi_GetHomePath=_SbieApi_GetHomePath@16
|
||||
SbieApi_GetUnmountHive=_SbieApi_GetUnmountHive@4
|
||||
SbieApi_GetVersion=_SbieApi_GetVersion@4
|
||||
SbieApi_GetWork=_SbieApi_GetWork@12
|
||||
;;; SbieApi_GetWork=_SbieApi_GetWork@12
|
||||
SbieApi_GetMessage=_SbieApi_GetMessage@20
|
||||
|
||||
SbieApi_HookTramp=_SbieApi_HookTramp@8
|
||||
|
||||
|
@ -34,6 +35,7 @@ SbieApi_IsBoxEnabled=_SbieApi_IsBoxEnabled@4
|
|||
|
||||
SbieApi_MonitorControl=_SbieApi_MonitorControl@8
|
||||
SbieApi_MonitorGet=_SbieApi_MonitorGet@8
|
||||
SbieApi_MonitorGetEx=_SbieApi_MonitorGetEx@16
|
||||
SbieApi_MonitorPut=_SbieApi_MonitorPut@8
|
||||
SbieApi_MonitorPut2=_SbieApi_MonitorPut2@12
|
||||
|
||||
|
|
|
@ -202,6 +202,7 @@ _FX int Debug_Init(void)
|
|||
// break
|
||||
//
|
||||
|
||||
OutputDebugString(L"Dll_ImageName: ");
|
||||
OutputDebugString(Dll_ImageName);
|
||||
|
||||
//if (_wcsicmp(Dll_ImageName, L"explorer.exe") == 0) {
|
||||
|
@ -223,7 +224,6 @@ _FX int Debug_Init(void)
|
|||
if (0)
|
||||
#endif
|
||||
{
|
||||
|
||||
while (! IsDebuggerPresent()) {
|
||||
OutputDebugString(L"BREAK\n");
|
||||
Sleep(500);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
|
||||
#undef WITH_DEBUG
|
||||
//#define WITH_DEBUG
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -35,7 +36,8 @@
|
|||
|
||||
#ifdef WITH_DEBUG
|
||||
|
||||
#define BREAK_IMAGE_1 L"java.exe" // L"jp2launcher.exe"
|
||||
//#define BREAK_IMAGE_1 L"java.exe" // L"jp2launcher.exe"
|
||||
#define BREAK_IMAGE_1 L"TestTarget.exe" // L"jp2launcher.exe"
|
||||
|
||||
int Debug_Init(void);
|
||||
|
||||
|
|
|
@ -211,6 +211,10 @@ _FX void Dll_InitInjected(void)
|
|||
ULONG BoxKeyPathLen;
|
||||
ULONG BoxIpcPathLen;
|
||||
|
||||
#ifdef WITH_DEBUG
|
||||
OutputDebugString(L"SbieDll: Dll_InitInjected");
|
||||
#endif WITH_DEBUG
|
||||
|
||||
//
|
||||
// confirm the process is sandboxed before going further
|
||||
//
|
||||
|
@ -690,7 +694,7 @@ _FX ULONG_PTR Dll_Ordinal1(
|
|||
{
|
||||
Ldr_Inject_Init(bHostInject);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// conclude the detour by passing control back to the original
|
||||
// RtlFindActivationContextSectionString. the detour code used
|
||||
|
|
|
@ -461,7 +461,7 @@ _FX NTSTATUS File_GetName(
|
|||
if (! NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
uni = &((OBJECT_NAME_INFORMATION *)name)->ObjectName;
|
||||
uni = &((OBJECT_NAME_INFORMATION *)name)->Name;
|
||||
|
||||
#ifdef WOW64_FS_REDIR
|
||||
//
|
||||
|
|
|
@ -1730,7 +1730,7 @@ _FX void File_GetSetDeviceMap(WCHAR *DeviceMap96)
|
|||
} else {
|
||||
|
||||
UNICODE_STRING *uni =
|
||||
&((OBJECT_NAME_INFORMATION *)dirname)->ObjectName;
|
||||
&((OBJECT_NAME_INFORMATION *)dirname)->Name;
|
||||
length = uni->Length / sizeof(WCHAR);
|
||||
if (length > 95)
|
||||
length = 95;
|
||||
|
|
|
@ -575,7 +575,7 @@ _FX NTSTATUS Ipc_GetName(
|
|||
if (! NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
*OutTruePath = ((OBJECT_NAME_INFORMATION *)name)->ObjectName.Buffer;
|
||||
*OutTruePath = ((OBJECT_NAME_INFORMATION *)name)->Name.Buffer;
|
||||
|
||||
if (! *OutTruePath) {
|
||||
|
||||
|
@ -588,7 +588,7 @@ _FX NTSTATUS Ipc_GetName(
|
|||
}
|
||||
|
||||
name = (*OutTruePath)
|
||||
+ ((OBJECT_NAME_INFORMATION *)name)->ObjectName.Length
|
||||
+ ((OBJECT_NAME_INFORMATION *)name)->Name.Length
|
||||
/ sizeof(WCHAR);
|
||||
|
||||
if (objname_len) {
|
||||
|
@ -972,10 +972,10 @@ _FX void Ipc_AdjustPortPath(UNICODE_STRING *ObjectName)
|
|||
status = Obj_GetObjectName(handle, name, &length);
|
||||
|
||||
if (NT_SUCCESS(status) &&
|
||||
name->ObjectName.Length >= ParentLength * sizeof(WCHAR) &&
|
||||
0 == _wcsnicmp(name->ObjectName.Buffer, Buffer, ParentLength)) {
|
||||
name->Name.Length >= ParentLength * sizeof(WCHAR) &&
|
||||
0 == _wcsnicmp(name->Name.Buffer, Buffer, ParentLength)) {
|
||||
|
||||
wmemcpy(Buffer, name->ObjectName.Buffer, ParentLength);
|
||||
wmemcpy(Buffer, name->Name.Buffer, ParentLength);
|
||||
}
|
||||
|
||||
Dll_Free(name);
|
||||
|
|
|
@ -399,7 +399,7 @@ _FX void Ldr_FixImagePath(void)
|
|||
|
||||
//
|
||||
// if this is a forced program, we need to get the image path from
|
||||
// the kernel (i.e. NtQueryVirtualMemory with MemorySectionName),
|
||||
// the kernel (i.e. NtQueryVirtualMemory with MemoryMappedFilenameInformation),
|
||||
// in case the image path contains symbolic links or reparse points.
|
||||
// such links would have been translated by NtCreateFile if the
|
||||
// program was started by another program in the sandbox. so if
|
||||
|
@ -471,7 +471,7 @@ _FX WCHAR *Ldr_FixImagePath_2(void)
|
|||
BufferLength = 256;
|
||||
NameUni = Dll_AllocTemp((ULONG)BufferLength + sizeof(WCHAR) * 2);
|
||||
status = __sys_NtQueryVirtualMemory(
|
||||
NtCurrentProcess(), (void *)Ldr_ImageBase, MemorySectionName,
|
||||
NtCurrentProcess(), (void *)Ldr_ImageBase, MemoryMappedFilenameInformation,
|
||||
NameUni, BufferLength, &BufferLength);
|
||||
|
||||
if (status == STATUS_INFO_LENGTH_MISMATCH ||
|
||||
|
@ -480,7 +480,7 @@ _FX WCHAR *Ldr_FixImagePath_2(void)
|
|||
Dll_Free(NameUni);
|
||||
NameUni = Dll_AllocTemp((ULONG)BufferLength + sizeof(WCHAR) * 2);
|
||||
status = __sys_NtQueryVirtualMemory(
|
||||
NtCurrentProcess(), (void *)Ldr_ImageBase, MemorySectionName,
|
||||
NtCurrentProcess(), (void *)Ldr_ImageBase, MemoryMappedFilenameInformation,
|
||||
NameUni, BufferLength, &BufferLength);
|
||||
}
|
||||
|
||||
|
|
|
@ -308,7 +308,7 @@ _FX NTSTATUS Obj_NtQueryVirtualMemory(
|
|||
// if the request is not for an object name, then call the system
|
||||
//
|
||||
|
||||
if (MemoryInformationClass != MemorySectionName) {
|
||||
if (MemoryInformationClass != MemoryMappedFilenameInformation) {
|
||||
|
||||
return __sys_NtQueryVirtualMemory(
|
||||
ProcessHandle, BaseAddress, MemoryInformationClass,
|
||||
|
@ -328,7 +328,7 @@ _FX NTSTATUS Obj_NtQueryVirtualMemory(
|
|||
}
|
||||
|
||||
status = __sys_NtQueryVirtualMemory(
|
||||
ProcessHandle, BaseAddress, MemorySectionName,
|
||||
ProcessHandle, BaseAddress, MemoryMappedFilenameInformation,
|
||||
name, maxlen, &outlen);
|
||||
|
||||
if (status == STATUS_INFO_LENGTH_MISMATCH ||
|
||||
|
@ -340,7 +340,7 @@ _FX NTSTATUS Obj_NtQueryVirtualMemory(
|
|||
name = Dll_AllocTemp((ULONG)maxlen);
|
||||
|
||||
status = __sys_NtQueryVirtualMemory(
|
||||
ProcessHandle, BaseAddress, MemorySectionName,
|
||||
ProcessHandle, BaseAddress, MemoryMappedFilenameInformation,
|
||||
name, maxlen, &outlen);
|
||||
}
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ _FX LONG SbieApi_GetVersion(
|
|||
// SbieApi_GetWork
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
_FX LONG SbieApi_GetWork(
|
||||
ULONG SessionId,
|
||||
void *Buffer,
|
||||
|
@ -273,6 +273,40 @@ _FX LONG SbieApi_GetWork(
|
|||
|
||||
return status;
|
||||
}
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// SbieApi_GetMessage
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX LONG SbieApi_GetMessage(
|
||||
ULONG* MessageNum,
|
||||
ULONG SessionId,
|
||||
ULONG *MessageId,
|
||||
wchar_t *Buffer,
|
||||
ULONG Length)
|
||||
{
|
||||
NTSTATUS status;
|
||||
__declspec(align(8)) UNICODE_STRING64 msgtext;
|
||||
__declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
|
||||
API_GET_MESSAGE_ARGS *args = (API_GET_MESSAGE_ARGS *)parms;
|
||||
|
||||
msgtext.MaximumLength = (USHORT)Length;
|
||||
msgtext.Buffer = (ULONG_PTR)Buffer;
|
||||
msgtext.Length = 0;
|
||||
|
||||
memzero(parms, sizeof(parms));
|
||||
args->func_code = API_GET_MESSAGE;
|
||||
args->msg_num.val = MessageNum;
|
||||
args->session_id.val = SessionId;
|
||||
args->msgid.val = MessageId;
|
||||
args->msgtext.val = &msgtext;
|
||||
|
||||
status = SbieApi_Ioctl(parms);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -1411,6 +1445,40 @@ _FX LONG SbieApi_MonitorGet(
|
|||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// SbieApi_MonitorGetEx
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX LONG SbieApi_MonitorGetEx(
|
||||
ULONG *SeqNum,
|
||||
USHORT *Type,
|
||||
ULONG64 *Pid,
|
||||
WCHAR *Name) // WCHAR [256]
|
||||
{
|
||||
NTSTATUS status;
|
||||
__declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
|
||||
API_MONITOR_GET_EX_ARGS *args = (API_MONITOR_GET_EX_ARGS *)parms;
|
||||
|
||||
args->func_code = API_MONITOR_GET_EX;
|
||||
args->name_seq.val64 = (ULONG64)(ULONG_PTR)SeqNum;
|
||||
args->name_type.val64 = (ULONG64)(ULONG_PTR)Type;
|
||||
args->name_pid.val64 = (ULONG64)(ULONG_PTR)Pid;
|
||||
args->name_len.val64 = 256 * sizeof(WCHAR);
|
||||
args->name_ptr.val64 = (ULONG64)(ULONG_PTR)Name;
|
||||
status = SbieApi_Ioctl(parms);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (Type)
|
||||
*Type = 0;
|
||||
if (Name)
|
||||
*Name = L'\0';
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// SbieApi_GetUnmountHive
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -62,11 +62,19 @@ SBIEAPI_EXPORT
|
|||
SBIEAPI_EXPORT LONG SbieApi_GetVersion(
|
||||
WCHAR *version_string); // WCHAR [16]
|
||||
|
||||
SBIEAPI_EXPORT
|
||||
/*SBIEAPI_EXPORT
|
||||
LONG SbieApi_GetWork(
|
||||
ULONG SessionId,
|
||||
void *Buffer,
|
||||
ULONG *Length);
|
||||
ULONG *Length);*/
|
||||
|
||||
SBIEAPI_EXPORT
|
||||
LONG SbieApi_GetMessage(
|
||||
ULONG* MessageNum,
|
||||
ULONG SessionId,
|
||||
ULONG *MessageId,
|
||||
wchar_t *Buffer,
|
||||
ULONG Length);
|
||||
|
||||
SBIEAPI_EXPORT LONG SbieApi_Log(
|
||||
ULONG msgid, const WCHAR *format, ...);
|
||||
|
@ -196,6 +204,13 @@ LONG SbieApi_MonitorGet(
|
|||
USHORT *Type,
|
||||
WCHAR *Name); // WCHAR [256]
|
||||
|
||||
SBIEAPI_EXPORT
|
||||
LONG SbieApi_MonitorGetEx(
|
||||
ULONG *SeqNum,
|
||||
USHORT *Type,
|
||||
ULONG64 *Pid,
|
||||
WCHAR *Name); // WCHAR [256]
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
@ -288,8 +303,6 @@ LONG SbieApi_QuerySymbolicLink(
|
|||
SBIEAPI_EXPORT
|
||||
LONG SbieApi_ReloadConf(ULONG session_id);
|
||||
|
||||
SBIEAPI_EXPORT
|
||||
LONG SbieApi_ReloadConf2(ULONG session_id, const WCHAR *config_path);
|
||||
|
||||
SBIEAPI_EXPORT
|
||||
LONG SbieApi_QueryConf(
|
||||
|
|
|
@ -825,7 +825,7 @@ _FX BOOL SbieDll_StartBoxedService(const WCHAR *ServiceName, BOOLEAN WithAdd)
|
|||
ULONG retries, error;
|
||||
|
||||
//WCHAR text[130];
|
||||
//Sbie_swprintf(text, L"StartBoxedService; name: '%s'; pid: %d", ServiceName, GetCurrentProcessId()); // fix-me: pottential buffer overflow
|
||||
//Sbie_swprintf(text, L"StartBoxedService; name: '%s'", ServiceName); // fix-me: pottential buffer overflow
|
||||
//SbieApi_MonitorPut(MONITOR_OTHER, text);
|
||||
|
||||
//
|
||||
|
@ -1096,7 +1096,7 @@ _FX BOOL Scm_StartServiceW(
|
|||
return FALSE;
|
||||
|
||||
WCHAR text[130];
|
||||
Sbie_swprintf(text, L"StartService; name: '%s'; pid: %d", ServiceName, GetCurrentProcessId()); // fix-me: pottential buffer overflow
|
||||
Sbie_swprintf(text, L"StartService: %s", ServiceName); // fix-me: pottential buffer overflow
|
||||
SbieApi_MonitorPut(MONITOR_OTHER, text);
|
||||
|
||||
if (Scm_IsBoxedService(ServiceName))
|
||||
|
@ -1263,7 +1263,7 @@ _FX BOOL Scm_StartServiceCtrlDispatcherX(
|
|||
}
|
||||
|
||||
//WCHAR text[130];
|
||||
//Sbie_swprintf(text, L"StartServiceCtrlDispatcher; name: '%s'; pid %d", ServiceName, GetCurrentProcessId()); // fix-me: pottential buffer overflow
|
||||
//Sbie_swprintf(text, L"StartServiceCtrlDispatcher; name: '%s'", ServiceName); // fix-me: pottential buffer overflow
|
||||
//SbieApi_MonitorPut(MONITOR_OTHER, text);
|
||||
|
||||
//
|
||||
|
|
|
@ -668,7 +668,7 @@ _FX NTSTATUS Secure_NtSetSecurityObject(
|
|||
OBJECT_NAME_INFORMATION *name =
|
||||
(OBJECT_NAME_INFORMATION *)name_space;
|
||||
status = Obj_GetObjectName(Handle, name, &name_len);
|
||||
if (NT_SUCCESS(status) && name->ObjectName.Length == 0) {
|
||||
if (NT_SUCCESS(status) && name->Name.Length == 0) {
|
||||
|
||||
IsUnnamedObject = TRUE;
|
||||
}
|
||||
|
|
|
@ -636,6 +636,7 @@ static UCHAR Support_BuiltinDomainRid[12] = {
|
|||
|
||||
#endif /* SBIEDLL_FORMATMESSAGE_ONLY */
|
||||
|
||||
#if 1
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// SbieDll_FormatMessage_2
|
||||
|
@ -844,3 +845,5 @@ _FX WCHAR *SbieDll_FormatMessage2(
|
|||
ins[2] = ins2;
|
||||
return SbieDll_FormatMessage(code, ins);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -304,6 +304,7 @@
|
|||
<ClCompile Include="process_hook.c" />
|
||||
<ClCompile Include="process_low.c" />
|
||||
<ClCompile Include="process_util.c" />
|
||||
<ClCompile Include="log_buff.c" />
|
||||
<ClCompile Include="session.c" />
|
||||
<ClCompile Include="syscall.c" />
|
||||
<ClCompile Include="syscall_32.c">
|
||||
|
@ -384,6 +385,7 @@
|
|||
<ClInclude Include="my_winnt.h" />
|
||||
<ClInclude Include="obj.h" />
|
||||
<ClInclude Include="process.h" />
|
||||
<ClInclude Include="log_buff.h" />
|
||||
<ClInclude Include="session.h" />
|
||||
<ClInclude Include="syscall.h" />
|
||||
<ClInclude Include="thread.h" />
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "util.h"
|
||||
#include "hook.h"
|
||||
#include "common/my_version.h"
|
||||
#include "log_buff.h"
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -49,7 +50,7 @@ static BOOLEAN Api_FastIo_DEVICE_CONTROL(
|
|||
ULONG IoControlCode, IO_STATUS_BLOCK *IoStatus,
|
||||
DEVICE_OBJECT *DeviceObject);
|
||||
|
||||
static void Api_DelWork(API_WORK_ITEM *work_item);
|
||||
//static void Api_DelWork(API_WORK_ITEM *work_item);
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -59,6 +60,8 @@ static NTSTATUS Api_GetVersion(PROCESS *proc, ULONG64 *parms);
|
|||
|
||||
static NTSTATUS Api_LogMessage(PROCESS *proc, ULONG64 *parms);
|
||||
|
||||
static NTSTATUS Api_GetMessage(PROCESS *proc, ULONG64 *parms);
|
||||
|
||||
static NTSTATUS Api_GetWork(PROCESS *proc, ULONG64 *parms);
|
||||
|
||||
static NTSTATUS Api_GetHomePath(PROCESS *proc, ULONG64 *parms);
|
||||
|
@ -92,9 +95,11 @@ volatile HANDLE Api_ServiceProcessId = NULL;
|
|||
|
||||
static PERESOURCE Api_LockResource = NULL;
|
||||
|
||||
static LIST Api_WorkList;
|
||||
//static LIST Api_WorkList;
|
||||
static BOOLEAN Api_WorkListInitialized = FALSE;
|
||||
|
||||
static LOG_BUFFER* Api_LogBuffer = NULL;
|
||||
|
||||
static volatile LONG Api_UseCount = -1;
|
||||
|
||||
|
||||
|
@ -108,11 +113,17 @@ _FX BOOLEAN Api_Init(void)
|
|||
NTSTATUS status;
|
||||
UNICODE_STRING uni;
|
||||
|
||||
//
|
||||
// initialize log buffer
|
||||
//
|
||||
|
||||
Api_LogBuffer = log_buffer_init(8 * 8 * 1024);
|
||||
|
||||
//
|
||||
// initialize work list
|
||||
//
|
||||
|
||||
List_Init(&Api_WorkList);
|
||||
//List_Init(&Api_WorkList);
|
||||
|
||||
if (! Mem_GetLockResource(&Api_LockResource, TRUE))
|
||||
return FALSE;
|
||||
|
@ -168,6 +179,7 @@ _FX BOOLEAN Api_Init(void)
|
|||
Api_SetFunction(API_GET_VERSION, Api_GetVersion);
|
||||
Api_SetFunction(API_GET_WORK, Api_GetWork);
|
||||
Api_SetFunction(API_LOG_MESSAGE, Api_LogMessage);
|
||||
Api_SetFunction(API_GET_MESSAGE, Api_GetMessage);
|
||||
Api_SetFunction(API_GET_HOME_PATH, Api_GetHomePath);
|
||||
Api_SetFunction(API_SET_SERVICE_PORT, Api_SetServicePort);
|
||||
|
||||
|
@ -195,8 +207,6 @@ _FX BOOLEAN Api_Init(void)
|
|||
|
||||
_FX void Api_Unload(void)
|
||||
{
|
||||
API_WORK_ITEM *work_item;
|
||||
|
||||
if (Api_DeviceObject) {
|
||||
IoDeleteDevice(Api_DeviceObject);
|
||||
Api_DeviceObject = NULL;
|
||||
|
@ -209,12 +219,18 @@ _FX void Api_Unload(void)
|
|||
|
||||
if (Api_WorkListInitialized) {
|
||||
|
||||
while (1) {
|
||||
if (Api_LogBuffer) {
|
||||
log_buffer_free(Api_LogBuffer);
|
||||
Api_LogBuffer = NULL;
|
||||
}
|
||||
|
||||
/*API_WORK_ITEM *work_item;
|
||||
while (1) {
|
||||
work_item = List_Head(&Api_WorkList);
|
||||
if (! work_item)
|
||||
break;
|
||||
Api_DelWork(work_item);
|
||||
}
|
||||
}*/
|
||||
|
||||
Mem_FreeLockResource(&Api_LockResource);
|
||||
|
||||
|
@ -612,6 +628,136 @@ _FX NTSTATUS Api_LogMessage(PROCESS *proc, ULONG64 *parms)
|
|||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Api_AddMessage
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX void Api_AddMessage(
|
||||
NTSTATUS error_code,
|
||||
const WCHAR *string1, ULONG string1_len,
|
||||
const WCHAR *string2, ULONG string2_len,
|
||||
ULONG session_id)
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
if (!Api_WorkListInitialized) // if (!Api_LogBuffer)
|
||||
return;
|
||||
|
||||
//
|
||||
// add work at the end of the work list
|
||||
//
|
||||
|
||||
irql = Api_EnterCriticalSection();
|
||||
|
||||
ULONG entry_size = sizeof(ULONG) // session_id
|
||||
+ sizeof(ULONG) // error_code
|
||||
+ (string1_len + 1) * sizeof(WCHAR)
|
||||
+ (string2_len + 1) * sizeof(WCHAR);
|
||||
|
||||
CHAR* write_ptr = log_buffer_push_entry((LOG_BUFFER_SIZE_T)entry_size, Api_LogBuffer);
|
||||
if (write_ptr) {
|
||||
//[session_id 4][error_code 4][string1 n*2][\0 2][string2 n*2][\0 2]
|
||||
WCHAR null_char = L'\0';
|
||||
log_buffer_push_bytes((CHAR*)&session_id, sizeof(ULONG), &write_ptr, Api_LogBuffer);
|
||||
log_buffer_push_bytes((CHAR*)&error_code, sizeof(ULONG), &write_ptr, Api_LogBuffer);
|
||||
log_buffer_push_bytes((CHAR*)string1, string1_len * sizeof(WCHAR), &write_ptr, Api_LogBuffer);
|
||||
log_buffer_push_bytes((CHAR*)&null_char, sizeof(WCHAR), &write_ptr, Api_LogBuffer);
|
||||
log_buffer_push_bytes((CHAR*)string2, string2_len * sizeof(WCHAR), &write_ptr, Api_LogBuffer);
|
||||
log_buffer_push_bytes((CHAR*)&null_char, sizeof(WCHAR), &write_ptr, Api_LogBuffer);
|
||||
}
|
||||
// else // this can only happen when the entire buffer is to small to hold this entire entry
|
||||
// if loging fails we can't log this error :/
|
||||
|
||||
Api_LeaveCriticalSection(irql);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Api_GetMessage
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX NTSTATUS Api_GetMessage(PROCESS *proc, ULONG64 *parms)
|
||||
{
|
||||
API_GET_MESSAGE_ARGS *args = (API_GET_MESSAGE_ARGS *)parms;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
UNICODE_STRING64 *msgtext;
|
||||
WCHAR *msgtext_buffer;
|
||||
KIRQL irql;
|
||||
|
||||
if (proc)
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
ProbeForRead(args->msg_num.val, sizeof(ULONG), sizeof(ULONG));
|
||||
ProbeForWrite(args->msg_num.val, sizeof(ULONG), sizeof(ULONG));
|
||||
|
||||
ProbeForWrite(args->msgid.val, sizeof(ULONG), sizeof(ULONG));
|
||||
|
||||
msgtext = args->msgtext.val;
|
||||
if (!msgtext)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
ProbeForRead(msgtext, sizeof(UNICODE_STRING64), sizeof(ULONG));
|
||||
ProbeForWrite(msgtext, sizeof(UNICODE_STRING64), sizeof(ULONG));
|
||||
|
||||
msgtext_buffer = (WCHAR *)msgtext->Buffer;
|
||||
if (!msgtext_buffer)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
irql = Api_EnterCriticalSection();
|
||||
|
||||
__try {
|
||||
|
||||
CHAR* read_ptr = log_buffer_get_next(*args->msg_num.val, Api_LogBuffer);
|
||||
|
||||
if (!read_ptr) {
|
||||
|
||||
status = STATUS_NO_MORE_ENTRIES;
|
||||
|
||||
} else {
|
||||
|
||||
LOG_BUFFER_SIZE_T entry_size = log_buffer_get_size(&read_ptr, Api_LogBuffer);
|
||||
LOG_BUFFER_SEQ_T seq_number = log_buffer_get_seq_num(&read_ptr, Api_LogBuffer);
|
||||
*args->msg_num.val = seq_number;
|
||||
//[session_id 4][error_code 4][string1 n*2][\0 2][string2 n*2][\0 2]
|
||||
ULONG session_id;
|
||||
log_buffer_get_bytes((CHAR*)&session_id, 4, &read_ptr, Api_LogBuffer);
|
||||
|
||||
if (session_id == args->session_id.val) {
|
||||
|
||||
log_buffer_get_bytes((CHAR*)args->msgid.val, 4, &read_ptr, Api_LogBuffer);
|
||||
SIZE_T msg_length = entry_size - (4 + 4);
|
||||
|
||||
if (msg_length <= msgtext->MaximumLength)
|
||||
{
|
||||
msgtext->Length = (USHORT)msg_length;
|
||||
ProbeForWrite(msgtext_buffer, msg_length, sizeof(WCHAR));
|
||||
memcpy(msgtext_buffer, read_ptr, msg_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
} else {
|
||||
// this entry is not for us, so we return an empty result to maintain sequence consistency
|
||||
|
||||
*args->msgid.val = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
|
||||
Api_LeaveCriticalSection(irql);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Api_SendServiceMessage
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -709,7 +855,7 @@ _FX BOOLEAN Api_SendServiceMessage(ULONG msgid, ULONG data_len, void *data)
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX BOOLEAN Api_AddWork(API_WORK_ITEM *work_item)
|
||||
/*_FX BOOLEAN Api_AddWork(API_WORK_ITEM *work_item)
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
|
@ -734,7 +880,7 @@ _FX BOOLEAN Api_AddWork(API_WORK_ITEM *work_item)
|
|||
return TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -742,13 +888,13 @@ _FX BOOLEAN Api_AddWork(API_WORK_ITEM *work_item)
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX void Api_DelWork(API_WORK_ITEM *work_item)
|
||||
/*_FX void Api_DelWork(API_WORK_ITEM *work_item)
|
||||
{
|
||||
// this assumes Api_WorkList is already locked using Api_Lock
|
||||
|
||||
List_Remove(&Api_WorkList, work_item);
|
||||
Mem_Free(work_item, work_item->length);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -758,7 +904,9 @@ _FX void Api_DelWork(API_WORK_ITEM *work_item)
|
|||
|
||||
_FX NTSTATUS Api_GetWork(PROCESS *proc, ULONG64 *parms)
|
||||
{
|
||||
API_GET_WORK_ARGS *args = (API_GET_WORK_ARGS *)parms;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
/*API_GET_WORK_ARGS *args = (API_GET_WORK_ARGS *)parms;
|
||||
NTSTATUS status;
|
||||
void *buffer_ptr;
|
||||
ULONG buffer_len;
|
||||
|
@ -834,7 +982,7 @@ _FX NTSTATUS Api_GetWork(PROCESS *proc, ULONG64 *parms)
|
|||
|
||||
Api_LeaveCriticalSection(irql);
|
||||
|
||||
return status;
|
||||
return status;*/
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef struct _API_WORK_ITEM {
|
||||
/*typedef struct _API_WORK_ITEM {
|
||||
|
||||
LIST_ELEM list_elem;
|
||||
ULONG length; // length includes both header and data
|
||||
|
@ -47,7 +47,7 @@ typedef struct _API_WORK_ITEM {
|
|||
|
||||
ULONG data[1];
|
||||
|
||||
} API_WORK_ITEM;
|
||||
} API_WORK_ITEM;*/
|
||||
|
||||
typedef struct _Sbie_SeFilterTokenArg
|
||||
{
|
||||
|
@ -110,7 +110,19 @@ BOOLEAN Api_SendServiceMessage(ULONG msgid, ULONG data_len, void *data);
|
|||
// allocate work_item from Driver_Pool, and initialize type, length and data
|
||||
//
|
||||
|
||||
BOOLEAN Api_AddWork(API_WORK_ITEM *work_item);
|
||||
//BOOLEAN Api_AddWork(API_WORK_ITEM *work_item);
|
||||
|
||||
|
||||
//
|
||||
// Add message to log buffer
|
||||
//
|
||||
|
||||
void Api_AddMessage(
|
||||
NTSTATUS error_code,
|
||||
const WCHAR *string1, ULONG string1_len,
|
||||
const WCHAR *string2, ULONG string2_len,
|
||||
ULONG session_id);
|
||||
|
||||
|
||||
//
|
||||
// Copies boxname parameter from user
|
||||
|
|
|
@ -147,6 +147,8 @@ enum {
|
|||
API_GET_WPAD_PORT,
|
||||
API_SET_GAME_CONFIG_STORE_PORT,
|
||||
API_SET_SMART_CARD_PORT,
|
||||
API_MONITOR_GET_EX,
|
||||
API_GET_MESSAGE,
|
||||
|
||||
API_LAST
|
||||
};
|
||||
|
@ -189,12 +191,12 @@ API_ARGS_FIELD(WCHAR *,string)
|
|||
API_ARGS_CLOSE(API_GET_VERSION_ARGS)
|
||||
|
||||
|
||||
API_ARGS_BEGIN(API_GET_WORK_ARGS)
|
||||
/*API_ARGS_BEGIN(API_GET_WORK_ARGS)
|
||||
API_ARGS_FIELD(ULONG,session_id)
|
||||
API_ARGS_FIELD(void *,buffer)
|
||||
API_ARGS_FIELD(ULONG,buffer_len)
|
||||
API_ARGS_FIELD(ULONG *,result_len_ptr)
|
||||
API_ARGS_CLOSE(API_GET_WORK_ARGS)
|
||||
API_ARGS_CLOSE(API_GET_WORK_ARGS)*/
|
||||
|
||||
|
||||
API_ARGS_BEGIN(API_LOG_MESSAGE_ARGS)
|
||||
|
@ -203,6 +205,12 @@ API_ARGS_FIELD(ULONG,msgid)
|
|||
API_ARGS_FIELD(UNICODE_STRING64 *,msgtext)
|
||||
API_ARGS_CLOSE(API_LOG_MESSAGE_ARGS)
|
||||
|
||||
API_ARGS_BEGIN(API_GET_MESSAGE_ARGS)
|
||||
API_ARGS_FIELD(ULONG *, msg_num)
|
||||
API_ARGS_FIELD(ULONG, session_id)
|
||||
API_ARGS_FIELD(ULONG *, msgid)
|
||||
API_ARGS_FIELD(UNICODE_STRING64 *, msgtext)
|
||||
API_ARGS_CLOSE(API_GET_MESSAGE_ARGS)
|
||||
|
||||
API_ARGS_BEGIN(API_QUERY_PROCESS_ARGS)
|
||||
API_ARGS_FIELD(HANDLE,process_id)
|
||||
|
@ -311,6 +319,14 @@ API_ARGS_FIELD(ULONG,name_len)
|
|||
API_ARGS_FIELD(WCHAR *,name_ptr)
|
||||
API_ARGS_CLOSE(API_MONITOR_GET_PUT_ARGS)
|
||||
|
||||
API_ARGS_BEGIN(API_MONITOR_GET_EX_ARGS)
|
||||
API_ARGS_FIELD(ULONG *, name_seq)
|
||||
API_ARGS_FIELD(USHORT *, name_type)
|
||||
API_ARGS_FIELD(ULONG64 *, name_pid)
|
||||
API_ARGS_FIELD(ULONG, name_len)
|
||||
API_ARGS_FIELD(WCHAR *, name_ptr)
|
||||
API_ARGS_CLOSE(API_MONITOR_GET_EX_ARGS)
|
||||
|
||||
API_ARGS_BEGIN(API_MONITOR_PUT2_ARGS)
|
||||
API_ARGS_FIELD(USHORT *,name_type)
|
||||
API_ARGS_FIELD(ULONG,name_len)
|
||||
|
|
|
@ -989,7 +989,7 @@ _FX NTSTATUS File_Generic_MyParseProc(
|
|||
|
||||
if (Session_MonitorCount &&
|
||||
device_type != FILE_DEVICE_PHYSICAL_NETCARD)
|
||||
Session_MonitorPut(MONITOR_IGNORE, ignore_str + 4);
|
||||
Session_MonitorPut(MONITOR_IGNORE, ignore_str + 4, proc->pid);
|
||||
|
||||
Mem_Free(ignore_str, ignore_str_len);
|
||||
}
|
||||
|
@ -1504,12 +1504,11 @@ skip_due_to_home_folder:
|
|||
mon_type |= MONITOR_OPEN;
|
||||
else
|
||||
mon_type |= MONITOR_DENY;
|
||||
Session_MonitorPut(mon_type, mon_name);
|
||||
Session_MonitorPut(mon_type, mon_name, proc->pid);
|
||||
|
||||
} else if (ShouldMonitorAccess) {
|
||||
|
||||
Session_MonitorPut(
|
||||
MONITOR_FILE_OR_KEY | MONITOR_DENY, Name->Name.Buffer);
|
||||
Session_MonitorPut(MONITOR_FILE_OR_KEY | MONITOR_DENY, Name->Name.Buffer, proc->pid);
|
||||
|
||||
} else if (msg1313 && status == STATUS_ACCESS_DENIED
|
||||
&& device_type == FILE_DEVICE_DISK
|
||||
|
|
|
@ -1334,7 +1334,7 @@ _FX ULONG_PTR Gui_NtUserPostThreadMessage(
|
|||
--nptr; *nptr = L':';
|
||||
--nptr; *nptr = L'$';
|
||||
|
||||
Session_MonitorPut(mon_type, nptr);
|
||||
Session_MonitorPut(mon_type, nptr, proc->pid);
|
||||
|
||||
Mem_Free(nbuf, nlen);
|
||||
}
|
||||
|
|
|
@ -940,7 +940,7 @@ _FX NTSTATUS Ipc_CheckGenericObject(
|
|||
mon_type |= MONITOR_OPEN;
|
||||
else
|
||||
mon_type |= MONITOR_DENY;
|
||||
Session_MonitorPut(mon_type, mon_name);
|
||||
Session_MonitorPut(mon_type, mon_name, proc->pid);
|
||||
}
|
||||
|
||||
// DbgPrint("Process <%06d> Status <%08X> Object <%S>\n", proc->pid, status, Name->Name.Buffer);
|
||||
|
|
|
@ -470,8 +470,7 @@ _FX NTSTATUS Key_MyParseProc_2(OBJ_PARSE_PROC_ARGS_2)
|
|||
|
||||
if (ShouldMonitorAccess) {
|
||||
|
||||
Session_MonitorPut(
|
||||
MONITOR_FILE_OR_KEY | MONITOR_DENY, Name->Name.Buffer);
|
||||
Session_MonitorPut(MONITOR_FILE_OR_KEY | MONITOR_DENY, Name->Name.Buffer, proc->pid);
|
||||
}
|
||||
|
||||
Mem_Free(Name, NameLength);
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "api.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Functions
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -36,11 +35,11 @@ static void Log_Event_Msg(
|
|||
const WCHAR *string1,
|
||||
const WCHAR *string2);
|
||||
|
||||
static void Log_Popup_Msg_2(
|
||||
/*static void Log_Popup_Msg_2(
|
||||
NTSTATUS error_code,
|
||||
const WCHAR *string1, ULONG string1_len,
|
||||
const WCHAR *string2, ULONG string2_len,
|
||||
ULONG session_id);
|
||||
ULONG session_id);*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -133,14 +132,16 @@ _FX void Log_Popup_Msg(
|
|||
if ((Driver_OsVersion >= DRIVER_WINDOWS_VISTA) && (session_id == 0))
|
||||
session_id = 1;
|
||||
|
||||
Log_Popup_Msg_2(
|
||||
//Log_Popup_Msg_2(
|
||||
Api_AddMessage(
|
||||
error_code, string1, string1_len, string2, string2_len, session_id);
|
||||
|
||||
//
|
||||
// log message to SbieSvc and trigger SbieSvc to wake up and collect it
|
||||
//
|
||||
|
||||
Log_Popup_Msg_2(
|
||||
//Log_Popup_Msg_2(
|
||||
Api_AddMessage(
|
||||
error_code, string1, string1_len, string2, string2_len, -1);
|
||||
|
||||
string1_len = 0;
|
||||
|
@ -155,7 +156,7 @@ _FX void Log_Popup_Msg(
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX void Log_Popup_Msg_2(
|
||||
/*_FX void Log_Popup_Msg_2(
|
||||
NTSTATUS error_code,
|
||||
const WCHAR *string1, ULONG string1_len,
|
||||
const WCHAR *string2, ULONG string2_len,
|
||||
|
@ -202,7 +203,7 @@ _FX void Log_Popup_Msg_2(
|
|||
|
||||
Api_AddWork(work_item);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "api.h"
|
||||
#include "process.h"
|
||||
#include "obj.h"
|
||||
#include "log_buff.h"
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -70,9 +71,7 @@ struct _SESSION {
|
|||
// resource monitor
|
||||
//
|
||||
|
||||
WCHAR *monitor_buf;
|
||||
WCHAR *monitor_read_ptr;
|
||||
WCHAR *monitor_write_ptr;
|
||||
LOG_BUFFER* monitor_log;
|
||||
|
||||
};
|
||||
|
||||
|
@ -110,6 +109,8 @@ static NTSTATUS Session_Api_MonitorPut2(PROCESS *proc, ULONG64 *parms);
|
|||
|
||||
static NTSTATUS Session_Api_MonitorGet(PROCESS *proc, ULONG64 *parms);
|
||||
|
||||
static NTSTATUS Session_Api_MonitorGetEx(PROCESS *proc, ULONG64 *parms);
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
@ -150,6 +151,7 @@ _FX BOOLEAN Session_Init(void)
|
|||
Api_SetFunction(API_MONITOR_PUT, Session_Api_MonitorPut);
|
||||
Api_SetFunction(API_MONITOR_PUT2, Session_Api_MonitorPut2);
|
||||
Api_SetFunction(API_MONITOR_GET, Session_Api_MonitorGet);
|
||||
Api_SetFunction(API_MONITOR_GET_EX, Session_Api_MonitorGetEx);
|
||||
|
||||
//
|
||||
// initialize set of recognized objects types for Session_Api_MonitorPut
|
||||
|
@ -338,8 +340,8 @@ _FX void Session_Cancel(HANDLE ProcessId)
|
|||
while (session) {
|
||||
if ((session->leader_pid == ProcessId) || (! ProcessId)) {
|
||||
|
||||
if (session->monitor_buf) {
|
||||
ExFreePoolWithTag(session->monitor_buf, tzuk);
|
||||
if (session->monitor_log) {
|
||||
log_buffer_free(session->monitor_log);
|
||||
InterlockedDecrement(&Session_MonitorCount);
|
||||
}
|
||||
|
||||
|
@ -573,7 +575,7 @@ _FX BOOLEAN Session_IsForceDisabled(ULONG SessionId)
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX void Session_MonitorPut(USHORT type, const WCHAR *name)
|
||||
_FX void Session_MonitorPut(USHORT type, const WCHAR *name, HANDLE pid)
|
||||
{
|
||||
SESSION *session;
|
||||
KIRQL irql;
|
||||
|
@ -582,41 +584,22 @@ _FX void Session_MonitorPut(USHORT type, const WCHAR *name)
|
|||
if (! session)
|
||||
return;
|
||||
|
||||
if (session->monitor_buf && *name) {
|
||||
if (session->monitor_log && *name) {
|
||||
|
||||
WCHAR *buf0 = session->monitor_buf;
|
||||
WCHAR *wptr = session->monitor_write_ptr;
|
||||
WCHAR *rptr = session->monitor_read_ptr;
|
||||
ULONG64 pid64 = (ULONG64)pid;
|
||||
SIZE_T data_len = (wcslen(name) + 1) * 2;
|
||||
|
||||
ULONG name_len = wcslen(name) + 1;
|
||||
//[Type 2][PID 8][Data n*2]
|
||||
SIZE_T entry_size = 2 + 8 + data_len;
|
||||
|
||||
BOOLEAN first = TRUE;
|
||||
|
||||
while (name_len) {
|
||||
|
||||
if (first) {
|
||||
first = FALSE;
|
||||
*wptr = type;
|
||||
} else {
|
||||
*wptr = *name;
|
||||
++name;
|
||||
--name_len;
|
||||
}
|
||||
|
||||
++wptr;
|
||||
if (wptr >= buf0 + SESSION_MONITOR_BUF_SIZE)
|
||||
wptr = buf0;
|
||||
if (wptr == rptr) {
|
||||
Log_Msg0(MSG_MONITOR_OVERFLOW);
|
||||
*buf0 = L'\0';
|
||||
wptr = buf0;
|
||||
session->monitor_read_ptr = buf0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*wptr = L'\0';
|
||||
session->monitor_write_ptr = wptr;
|
||||
CHAR* write_ptr = log_buffer_push_entry((LOG_BUFFER_SIZE_T)entry_size, session->monitor_log);
|
||||
if (write_ptr) {
|
||||
log_buffer_push_bytes((CHAR*)&type, 2, &write_ptr, session->monitor_log);
|
||||
log_buffer_push_bytes((CHAR*)&pid64, 8, &write_ptr, session->monitor_log);
|
||||
log_buffer_push_bytes((CHAR*)name, data_len, &write_ptr, session->monitor_log);
|
||||
}
|
||||
else // this can only happen when the entire buffer is to small to hold this entire entry
|
||||
Log_Msg0(MSG_MONITOR_OVERFLOW);
|
||||
}
|
||||
|
||||
Session_Unlock(irql);
|
||||
|
@ -650,7 +633,7 @@ _FX NTSTATUS Session_Api_MonitorControl(PROCESS *proc, ULONG64 *parms)
|
|||
*out_flag = FALSE;
|
||||
session = Session_Get(FALSE, -1, &irql);
|
||||
if (session) {
|
||||
if (session->monitor_buf)
|
||||
if (session->monitor_log)
|
||||
*out_flag = TRUE;
|
||||
Session_Unlock(irql);
|
||||
}
|
||||
|
@ -676,24 +659,18 @@ _FX NTSTATUS Session_Api_MonitorControl(PROCESS *proc, ULONG64 *parms)
|
|||
session = Session_Get(FALSE, -1, &irql);
|
||||
if (session) {
|
||||
|
||||
if (EnableMonitor && (! session->monitor_buf)) {
|
||||
if (EnableMonitor && (! session->monitor_log)) {
|
||||
|
||||
session->monitor_buf = ExAllocatePoolWithTag(PagedPool,
|
||||
SESSION_MONITOR_BUF_SIZE * sizeof(WCHAR), tzuk);
|
||||
session->monitor_write_ptr = session->monitor_buf;
|
||||
session->monitor_read_ptr = session->monitor_buf;
|
||||
if (session->monitor_buf) {
|
||||
*session->monitor_buf = L'\0';
|
||||
session->monitor_log = log_buffer_init(SESSION_MONITOR_BUF_SIZE * sizeof(WCHAR));
|
||||
if (session->monitor_log) {
|
||||
InterlockedIncrement(&Session_MonitorCount);
|
||||
} else
|
||||
Log_Msg0(MSG_1201);
|
||||
|
||||
} else if ((! EnableMonitor) && session->monitor_buf) {
|
||||
} else if ((! EnableMonitor) && session->monitor_log) {
|
||||
|
||||
ExFreePoolWithTag(session->monitor_buf, tzuk);
|
||||
session->monitor_buf = NULL;
|
||||
session->monitor_write_ptr = session->monitor_buf;
|
||||
session->monitor_read_ptr = session->monitor_buf;
|
||||
log_buffer_free(session->monitor_log);
|
||||
session->monitor_log = NULL;
|
||||
InterlockedDecrement(&Session_MonitorCount);
|
||||
}
|
||||
|
||||
|
@ -895,7 +872,7 @@ _FX NTSTATUS Session_Api_MonitorPut2(PROCESS *proc, ULONG64 *parms)
|
|||
name[1] = L'\0';
|
||||
}
|
||||
|
||||
Session_MonitorPut(type, name);
|
||||
Session_MonitorPut(type, name, proc->pid);
|
||||
}
|
||||
|
||||
Mem_Free(name, 260 * sizeof(WCHAR));
|
||||
|
@ -908,12 +885,25 @@ _FX NTSTATUS Session_Api_MonitorPut2(PROCESS *proc, ULONG64 *parms)
|
|||
// Session_Api_MonitorGet
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX NTSTATUS Session_Api_MonitorGet(PROCESS *proc, ULONG64 *parms)
|
||||
{
|
||||
API_MONITOR_GET_PUT_ARGS *args = (API_MONITOR_GET_PUT_ARGS *)parms;
|
||||
API_MONITOR_GET_PUT_ARGS *args = (API_MONITOR_GET_PUT_ARGS *)parms;
|
||||
API_MONITOR_GET_EX_ARGS args2 = { args->func_code, 0, args->name_type.val64, 0, args->name_len.val64, args->name_ptr.val64 };
|
||||
|
||||
return Session_Api_MonitorGetEx(proc, (ULONG64*)&args2);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Session_Api_MonitorGet
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
_FX NTSTATUS Session_Api_MonitorGetEx(PROCESS *proc, ULONG64 *parms)
|
||||
{
|
||||
API_MONITOR_GET_EX_ARGS *args = (API_MONITOR_GET_EX_ARGS *)parms;
|
||||
NTSTATUS status;
|
||||
ULONG *seq_num;
|
||||
USHORT *user_type;
|
||||
ULONG64 *user_pid;
|
||||
ULONG name_len;
|
||||
WCHAR *user_name;
|
||||
SESSION *session;
|
||||
|
@ -922,9 +912,19 @@ _FX NTSTATUS Session_Api_MonitorGet(PROCESS *proc, ULONG64 *parms)
|
|||
if (proc)
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
seq_num = args->name_seq.val;
|
||||
if (seq_num != NULL) {
|
||||
ProbeForRead(seq_num, sizeof(ULONG), sizeof(ULONG));
|
||||
ProbeForWrite(seq_num, sizeof(ULONG), sizeof(ULONG));
|
||||
}
|
||||
|
||||
user_type = args->name_type.val;
|
||||
ProbeForWrite(user_type, sizeof(USHORT), sizeof(USHORT));
|
||||
|
||||
user_pid = args->name_pid.val;
|
||||
if(user_pid != NULL)
|
||||
ProbeForWrite(user_pid, sizeof(ULONG64), sizeof(ULONG64));
|
||||
|
||||
name_len = args->name_len.val / sizeof(WCHAR);
|
||||
if ((! name_len) || name_len > 256)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
@ -932,6 +932,8 @@ _FX NTSTATUS Session_Api_MonitorGet(PROCESS *proc, ULONG64 *parms)
|
|||
ProbeForWrite(user_name, name_len * sizeof(WCHAR), sizeof(WCHAR));
|
||||
|
||||
*user_type = 0;
|
||||
if (user_pid != NULL)
|
||||
*user_pid = 0;
|
||||
*user_name = L'\0';
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
|
@ -941,39 +943,31 @@ _FX NTSTATUS Session_Api_MonitorGet(PROCESS *proc, ULONG64 *parms)
|
|||
|
||||
__try {
|
||||
|
||||
if (session->monitor_buf) {
|
||||
if (session->monitor_log) {
|
||||
|
||||
WCHAR *buf0 = session->monitor_buf;
|
||||
WCHAR *rptr = session->monitor_read_ptr;
|
||||
BOOLEAN first = TRUE;
|
||||
CHAR* read_ptr = NULL;
|
||||
if (seq_num != NULL)
|
||||
read_ptr = log_buffer_get_next(*seq_num, session->monitor_log);
|
||||
else if (session->monitor_log->buffer_size > 0) // for compatybility with older versions we return the oldest entry
|
||||
read_ptr = session->monitor_log->buffer_start_ptr;
|
||||
|
||||
if (*rptr) {
|
||||
if (read_ptr != NULL) {
|
||||
LOG_BUFFER_SIZE_T entry_size = log_buffer_get_size(&read_ptr, session->monitor_log);
|
||||
LOG_BUFFER_SEQ_T seq_number = log_buffer_get_seq_num(&read_ptr, session->monitor_log);
|
||||
if (seq_num != NULL)
|
||||
*seq_num = seq_number;
|
||||
//[Type 2][PID 8][Data n*2]
|
||||
log_buffer_get_bytes((CHAR*)user_type, 2, &read_ptr, session->monitor_log);
|
||||
ULONG64 pid64;
|
||||
log_buffer_get_bytes((CHAR*)&pid64, 8, &read_ptr, session->monitor_log);
|
||||
if (user_pid != NULL)
|
||||
*user_pid = pid64;
|
||||
log_buffer_get_bytes((CHAR*)user_name, entry_size - (2 + 8), &read_ptr, session->monitor_log);
|
||||
}
|
||||
|
||||
while (*rptr) {
|
||||
|
||||
if (first) {
|
||||
first = FALSE;
|
||||
*user_type = *rptr;
|
||||
} else if (name_len) {
|
||||
*user_name = *rptr;
|
||||
++user_name;
|
||||
--name_len;
|
||||
} else
|
||||
status = STATUS_BUFFER_OVERFLOW;
|
||||
|
||||
++rptr;
|
||||
if (rptr >= buf0 + SESSION_MONITOR_BUF_SIZE)
|
||||
rptr = buf0;
|
||||
}
|
||||
|
||||
++rptr;
|
||||
if (rptr >= buf0 + SESSION_MONITOR_BUF_SIZE)
|
||||
rptr = buf0;
|
||||
session->monitor_read_ptr = rptr;
|
||||
|
||||
if (name_len)
|
||||
*user_name = L'\0';
|
||||
}
|
||||
// for compatybility with older versions we fall back to clearing the returned entry
|
||||
if (seq_num != NULL)
|
||||
log_buffer_pop_entry(session->monitor_log);
|
||||
}
|
||||
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
|
|
|
@ -41,7 +41,7 @@ void Session_Cancel(HANDLE ProcessId);
|
|||
|
||||
BOOLEAN Session_IsForceDisabled(ULONG SessionId);
|
||||
|
||||
void Session_MonitorPut(USHORT type, const WCHAR *name);
|
||||
void Session_MonitorPut(USHORT type, const WCHAR *name, HANDLE pid);
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -1034,7 +1034,7 @@ _FX NTSTATUS Thread_CheckObject_Common(
|
|||
--nptr; *nptr = L':';
|
||||
--nptr; *nptr = L'$';
|
||||
|
||||
Session_MonitorPut(mon_type, nptr);
|
||||
Session_MonitorPut(mon_type, nptr, proc->pid);
|
||||
|
||||
Mem_Free(nbuf, nlen);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ DriverAssist::DriverAssist()
|
|||
m_Threads = NULL;
|
||||
m_DriverReady = false;
|
||||
|
||||
m_last_message_number = 0;
|
||||
|
||||
InitializeCriticalSection(&m_LogMessage_CritSec);
|
||||
InitializeCriticalSection(&m_critSecHostInjectedSvcs);
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ private:
|
|||
|
||||
void LogMessage();
|
||||
|
||||
void LogMessage_Single(void *data);
|
||||
void LogMessage_Single(ULONG code, wchar_t* data);
|
||||
void LogMessage_Multi(ULONG msgid, const WCHAR *path, const WCHAR *text);
|
||||
void LogMessage_Write(const WCHAR *path, const WCHAR *text);
|
||||
|
||||
|
@ -139,6 +139,8 @@ private:
|
|||
|
||||
volatile bool m_DriverReady;
|
||||
|
||||
ULONG m_last_message_number;
|
||||
|
||||
//
|
||||
// critical sections
|
||||
//
|
||||
|
|
|
@ -50,7 +50,9 @@ void DriverAssist::LogMessage()
|
|||
break;
|
||||
|
||||
ULONG len = m_workItemLen;
|
||||
ULONG status = SbieApi_GetWork(-1, m_workItemBuf, &len);
|
||||
ULONG message_number = m_last_message_number;
|
||||
ULONG code = -1;
|
||||
ULONG status = SbieApi_GetMessage(&message_number, -1, &code, (wchar_t*)m_workItemBuf, len);
|
||||
|
||||
if (status == STATUS_BUFFER_TOO_SMALL) {
|
||||
HeapFree(GetProcessHeap(), 0, m_workItemBuf);
|
||||
|
@ -60,11 +62,16 @@ void DriverAssist::LogMessage()
|
|||
}
|
||||
|
||||
if (status != 0)
|
||||
break;
|
||||
break; // error or no more entries
|
||||
|
||||
WORK_ITEM *work = (WORK_ITEM *)m_workItemBuf;
|
||||
if (work->type == API_LOG_MESSAGE)
|
||||
LogMessage_Single(work->data);
|
||||
//if (message_number != m_last_message_number + 1)
|
||||
// we missed something
|
||||
m_last_message_number = message_number;
|
||||
|
||||
if (code == 0)
|
||||
break; // empty dummy
|
||||
|
||||
LogMessage_Single(code, (wchar_t*)m_workItemBuf);
|
||||
}
|
||||
|
||||
if (m_workItemBuf)
|
||||
|
@ -79,7 +86,7 @@ void DriverAssist::LogMessage()
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
void DriverAssist::LogMessage_Single(void *data)
|
||||
void DriverAssist::LogMessage_Single(ULONG code, wchar_t* data)
|
||||
{
|
||||
//
|
||||
// check if logging is enabled
|
||||
|
@ -108,16 +115,15 @@ void DriverAssist::LogMessage_Single(void *data)
|
|||
// get log message
|
||||
//
|
||||
|
||||
ULONG *msgidptr = (ULONG *)data;
|
||||
if (*msgidptr == MSG_2199)
|
||||
if (code == MSG_2199)
|
||||
return;
|
||||
|
||||
WCHAR *str1 = (WCHAR *)(msgidptr + 1);
|
||||
WCHAR *str1 = data;
|
||||
ULONG str1_len = wcslen(str1);
|
||||
WCHAR *str2 = str1 + str1_len + 1;
|
||||
ULONG str2_len = wcslen(str2);
|
||||
|
||||
WCHAR *text = SbieDll_FormatMessage2(*msgidptr, str1, str2);
|
||||
WCHAR *text = SbieDll_FormatMessage2(code, str1, str2);
|
||||
if (! text)
|
||||
return;
|
||||
|
||||
|
@ -152,7 +158,7 @@ void DriverAssist::LogMessage_Single(void *data)
|
|||
|
||||
LogMessage_Write(path, text);
|
||||
|
||||
LogMessage_Multi(*msgidptr, path, text);
|
||||
LogMessage_Multi(code, path, text);
|
||||
|
||||
LocalFree(text);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ echo. > %OUTPUT%
|
|||
|
||||
for /F "tokens=3*" %%A in ('findstr /R "^#define.SBIE_INSTALLER_PATH\>" %INPUT%') do ( echo ^^!define SBIE_INSTALLER_PATH %%A) >> %OUTPUT%
|
||||
|
||||
for /F "tokens=3*" %%A in ('findstr /R "^#define.MY_VERSION_STRING\>" %INPUT%') do ( echo ^^!define VERSION %%A) >> %OUTPUT%
|
||||
for /F "tokens=3*" %%A in ('findstr /R "^#define.MY_VERSION_STRING_EX\>" %INPUT%') do ( echo ^^!define VERSION %%A) >> %OUTPUT%
|
||||
|
||||
for /F "tokens=3*" %%A in ('findstr /R "^#define.MY_PRODUCT_NAME_STRING\>" %INPUT%') do ( set C=%%A %%B& echo ^^!define PRODUCT_FULL_NAME !C! & set C=!C: =!& echo ^^!define PRODUCT_NAME !C!) >> %OUTPUT%
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ SetCompressor /SOLID /FINAL lzma
|
|||
;----------------------------------------------------------------------------
|
||||
; these are the build-time config settings. Need to be cmd line args or something better.
|
||||
; pick either 32 or 64 bit
|
||||
!define _BUILDARCH Win32
|
||||
;!define _BUILDARCH x64
|
||||
;!define _BUILDARCH Win32
|
||||
!define _BUILDARCH x64
|
||||
|
||||
; uncomment this line if you want to make the special versions that download VC Redist
|
||||
;!define INCLUDE_VCREDIST_DNLD
|
||||
|
@ -764,21 +764,21 @@ FunctionEnd
|
|||
; We download various files during install just to keep stats on activity
|
||||
|
||||
Function DownloadStatPng
|
||||
|
||||
Pop $0 ; Get the parameter (file name to download)
|
||||
${If} ${RunningX64}
|
||||
SetRegView 64
|
||||
${EndIf}
|
||||
ReadRegStr $1 HKLM "SOFTWARE\Microsoft\Cryptography" "MachineGuid"
|
||||
StrCpy $2 "https://www.sandboxie.com/img/$0?SessionId=$1"
|
||||
|
||||
;NSISdl::download_quiet /TIMEOUT=3000 $2 $TEMP\$0
|
||||
inetc::get /SILENT /CONNECTTIMEOUT=5000 /RECEIVETIMEOUT=5000 $2 $TEMP\$0 /END
|
||||
Pop $0 ;Get the return value
|
||||
;MessageBox MB_OK|MB_ICONSTOP "DownloadStatPng: $2$\n$0"
|
||||
${If} ${RunningX64}
|
||||
SetRegView 32
|
||||
${EndIf}
|
||||
;
|
||||
; Pop $0 ; Get the parameter (file name to download)
|
||||
; ${If} ${RunningX64}
|
||||
; SetRegView 64
|
||||
; ${EndIf}
|
||||
; ReadRegStr $1 HKLM "SOFTWARE\Microsoft\Cryptography" "MachineGuid"
|
||||
; StrCpy $2 "https://www.sandboxie.com/img/$0?SessionId=$1"
|
||||
;
|
||||
; ;NSISdl::download_quiet /TIMEOUT=3000 $2 $TEMP\$0
|
||||
; inetc::get /SILENT /CONNECTTIMEOUT=5000 /RECEIVETIMEOUT=5000 $2 $TEMP\$0 /END
|
||||
; Pop $0 ;Get the return value
|
||||
; ;MessageBox MB_OK|MB_ICONSTOP "DownloadStatPng: $2$\n$0"
|
||||
; ${If} ${RunningX64}
|
||||
; SetRegView 32
|
||||
; ${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
|
||||
|
|
|
@ -70,9 +70,7 @@
|
|||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">
|
||||
<LibraryPath>$(WDKPATH)\lib\crt\amd64;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
#include "stdafx.h"
|
||||
#include "CheckableMessageBox.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QDebug>
|
||||
|
||||
/*!
|
||||
\class Utils::CCheckableMessageBox
|
||||
|
||||
\brief A messagebox suitable for questions with a
|
||||
"Do not ask me again" checkbox.
|
||||
|
||||
Emulates the QMessageBox API with
|
||||
static conveniences. The message label can open external URLs.
|
||||
*/
|
||||
|
||||
|
||||
class CCheckableMessageBoxPrivate
|
||||
{
|
||||
public:
|
||||
CCheckableMessageBoxPrivate(QDialog *q)
|
||||
: clickedButton(0)
|
||||
{
|
||||
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
||||
|
||||
pixmapLabel = new QLabel(q);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
|
||||
pixmapLabel->setSizePolicy(sizePolicy);
|
||||
pixmapLabel->setVisible(false);
|
||||
|
||||
QSpacerItem *pixmapSpacer =
|
||||
new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
|
||||
|
||||
messageLabel = new QLabel(q);
|
||||
messageLabel->setMinimumSize(QSize(300, 0));
|
||||
messageLabel->setSizePolicy(QSizePolicy::Expanding, messageLabel->sizePolicy().verticalPolicy());
|
||||
messageLabel->setWordWrap(true);
|
||||
messageLabel->setOpenExternalLinks(true);
|
||||
messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
|
||||
|
||||
QSpacerItem *checkBoxRightSpacer =
|
||||
new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
QSpacerItem *buttonSpacer =
|
||||
new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
|
||||
checkBox = new QCheckBox(q);
|
||||
checkBox->setText(CCheckableMessageBox::tr("Do not ask again"));
|
||||
|
||||
buttonBox = new QDialogButtonBox(q);
|
||||
buttonBox->setOrientation(Qt::Horizontal);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
|
||||
QVBoxLayout *verticalLayout = new QVBoxLayout();
|
||||
verticalLayout->addWidget(pixmapLabel);
|
||||
verticalLayout->addItem(pixmapSpacer);
|
||||
|
||||
QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
|
||||
horizontalLayout_2->addLayout(verticalLayout);
|
||||
horizontalLayout_2->addWidget(messageLabel);
|
||||
|
||||
QHBoxLayout *horizontalLayout = new QHBoxLayout();
|
||||
horizontalLayout->addWidget(checkBox);
|
||||
horizontalLayout->addItem(checkBoxRightSpacer);
|
||||
|
||||
QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q);
|
||||
verticalLayout_2->addLayout(horizontalLayout_2);
|
||||
verticalLayout_2->addLayout(horizontalLayout);
|
||||
verticalLayout_2->addItem(buttonSpacer);
|
||||
verticalLayout_2->addWidget(buttonBox);
|
||||
}
|
||||
|
||||
QLabel *pixmapLabel;
|
||||
QLabel *messageLabel;
|
||||
QCheckBox *checkBox;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QAbstractButton *clickedButton;
|
||||
};
|
||||
|
||||
CCheckableMessageBox::CCheckableMessageBox(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
d(new CCheckableMessageBoxPrivate(this))
|
||||
{
|
||||
setModal(true);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
|
||||
connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
||||
connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)),
|
||||
SLOT(slotClicked(QAbstractButton*)));
|
||||
}
|
||||
|
||||
CCheckableMessageBox::~CCheckableMessageBox()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void CCheckableMessageBox::slotClicked(QAbstractButton *b)
|
||||
{
|
||||
d->clickedButton = b;
|
||||
}
|
||||
|
||||
QAbstractButton *CCheckableMessageBox::clickedButton() const
|
||||
{
|
||||
return d->clickedButton;
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CCheckableMessageBox::clickedStandardButton() const
|
||||
{
|
||||
if (d->clickedButton)
|
||||
return d->buttonBox->standardButton(d->clickedButton);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
QString CCheckableMessageBox::text() const
|
||||
{
|
||||
return d->messageLabel->text();
|
||||
}
|
||||
|
||||
void CCheckableMessageBox::setText(const QString &t)
|
||||
{
|
||||
d->messageLabel->setText(t);
|
||||
}
|
||||
|
||||
QPixmap CCheckableMessageBox::iconPixmap() const
|
||||
{
|
||||
if (const QPixmap *p = d->pixmapLabel->pixmap())
|
||||
return QPixmap(*p);
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
void CCheckableMessageBox::setIconPixmap(const QPixmap &p)
|
||||
{
|
||||
d->pixmapLabel->setPixmap(p);
|
||||
d->pixmapLabel->setVisible(!p.isNull());
|
||||
}
|
||||
|
||||
bool CCheckableMessageBox::isChecked() const
|
||||
{
|
||||
return d->checkBox->isChecked();
|
||||
}
|
||||
|
||||
void CCheckableMessageBox::setChecked(bool s)
|
||||
{
|
||||
d->checkBox->setChecked(s);
|
||||
}
|
||||
|
||||
QString CCheckableMessageBox::checkBoxText() const
|
||||
{
|
||||
return d->checkBox->text();
|
||||
}
|
||||
|
||||
void CCheckableMessageBox::setCheckBoxText(const QString &t)
|
||||
{
|
||||
d->checkBox->setText(t);
|
||||
}
|
||||
|
||||
bool CCheckableMessageBox::isCheckBoxVisible() const
|
||||
{
|
||||
return d->checkBox->isVisible();
|
||||
}
|
||||
|
||||
void CCheckableMessageBox::setCheckBoxVisible(bool v)
|
||||
{
|
||||
d->checkBox->setVisible(v);
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButtons CCheckableMessageBox::standardButtons() const
|
||||
{
|
||||
return d->buttonBox->standardButtons();
|
||||
}
|
||||
|
||||
void CCheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s)
|
||||
{
|
||||
d->buttonBox->setStandardButtons(s);
|
||||
}
|
||||
|
||||
QPushButton *CCheckableMessageBox::button(QDialogButtonBox::StandardButton b) const
|
||||
{
|
||||
return d->buttonBox->button(b);
|
||||
}
|
||||
|
||||
QPushButton *CCheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
|
||||
{
|
||||
return d->buttonBox->addButton(text, role);
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CCheckableMessageBox::defaultButton() const
|
||||
{
|
||||
foreach (QAbstractButton *b, d->buttonBox->buttons())
|
||||
if (QPushButton *pb = qobject_cast<QPushButton *>(b))
|
||||
if (pb->isDefault())
|
||||
return d->buttonBox->standardButton(pb);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
void CCheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s)
|
||||
{
|
||||
if (QPushButton *b = d->buttonBox->button(s)) {
|
||||
b->setDefault(true);
|
||||
b->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton
|
||||
CCheckableMessageBox::question(QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &question,
|
||||
const QString &checkBoxText,
|
||||
bool *checkBoxSetting,
|
||||
QDialogButtonBox::StandardButtons buttons,
|
||||
QDialogButtonBox::StandardButton defaultButton,
|
||||
QMessageBox::Icon icon)
|
||||
{
|
||||
CCheckableMessageBox mb(parent);
|
||||
mb.setWindowTitle(title);
|
||||
mb.setIconPixmap(QMessageBox::standardIcon(icon));
|
||||
mb.setText(question);
|
||||
mb.setCheckBoxText(checkBoxText);
|
||||
mb.setChecked(*checkBoxSetting);
|
||||
mb.setStandardButtons(buttons);
|
||||
mb.setDefaultButton(defaultButton);
|
||||
mb.exec();
|
||||
*checkBoxSetting = mb.isChecked();
|
||||
return mb.clickedStandardButton();
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton CCheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db)
|
||||
{
|
||||
return static_cast<QMessageBox::StandardButton>(int(db));
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#ifndef CHECKABLEMESSAGEBOX_H
|
||||
#define CHECKABLEMESSAGEBOX_H
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QMessageBox>
|
||||
|
||||
class CCheckableMessageBoxPrivate;
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CCheckableMessageBox : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
|
||||
Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked)
|
||||
Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton)
|
||||
|
||||
public:
|
||||
explicit CCheckableMessageBox(QWidget *parent = NULL);
|
||||
virtual ~CCheckableMessageBox();
|
||||
|
||||
static QDialogButtonBox::StandardButton
|
||||
question(QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &question,
|
||||
const QString &checkBoxText,
|
||||
bool *checkBoxSetting,
|
||||
QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No,
|
||||
QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No,
|
||||
QMessageBox::Icon icon = QMessageBox::Question);
|
||||
|
||||
QString text() const;
|
||||
void setText(const QString &);
|
||||
|
||||
bool isChecked() const;
|
||||
void setChecked(bool s);
|
||||
|
||||
QString checkBoxText() const;
|
||||
void setCheckBoxText(const QString &);
|
||||
|
||||
bool isCheckBoxVisible() const;
|
||||
void setCheckBoxVisible(bool);
|
||||
|
||||
QDialogButtonBox::StandardButtons standardButtons() const;
|
||||
void setStandardButtons(QDialogButtonBox::StandardButtons s);
|
||||
QPushButton *button(QDialogButtonBox::StandardButton b) const;
|
||||
QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role);
|
||||
|
||||
QDialogButtonBox::StandardButton defaultButton() const;
|
||||
void setDefaultButton(QDialogButtonBox::StandardButton s);
|
||||
|
||||
// See static QMessageBox::standardPixmap()
|
||||
QPixmap iconPixmap() const;
|
||||
void setIconPixmap (const QPixmap &p);
|
||||
|
||||
// Query the result
|
||||
QAbstractButton *clickedButton() const;
|
||||
QDialogButtonBox::StandardButton clickedStandardButton() const;
|
||||
|
||||
// Conversion convenience
|
||||
static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton);
|
||||
|
||||
private slots:
|
||||
void slotClicked(QAbstractButton *b);
|
||||
|
||||
private:
|
||||
CCheckableMessageBoxPrivate *d;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // CHECKABLEMESSAGEBOX_H
|
|
@ -0,0 +1,193 @@
|
|||
#include "stdafx.h"
|
||||
#include "ComboInputDialog.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
class CComboInputDialogPrivate
|
||||
{
|
||||
public:
|
||||
CComboInputDialogPrivate(QDialog *q)
|
||||
: clickedButton(0)
|
||||
{
|
||||
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
||||
|
||||
pixmapLabel = new QLabel(q);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
|
||||
pixmapLabel->setSizePolicy(sizePolicy);
|
||||
pixmapLabel->setVisible(false);
|
||||
|
||||
QSpacerItem *pixmapSpacer =
|
||||
new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
|
||||
|
||||
messageLabel = new QLabel(q);
|
||||
messageLabel->setMinimumSize(QSize(300, 0));
|
||||
messageLabel->setWordWrap(true);
|
||||
messageLabel->setOpenExternalLinks(true);
|
||||
messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
|
||||
|
||||
QSpacerItem *buttonSpacer =
|
||||
new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
|
||||
combo = new QComboBox(q);
|
||||
|
||||
|
||||
buttonBox = new QDialogButtonBox(q);
|
||||
buttonBox->setOrientation(Qt::Horizontal);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
|
||||
QVBoxLayout *verticalLayout = new QVBoxLayout();
|
||||
verticalLayout->addWidget(pixmapLabel);
|
||||
verticalLayout->addItem(pixmapSpacer);
|
||||
|
||||
QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
|
||||
horizontalLayout_2->addLayout(verticalLayout);
|
||||
horizontalLayout_2->addWidget(messageLabel);
|
||||
|
||||
QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q);
|
||||
verticalLayout_2->addLayout(horizontalLayout_2);
|
||||
verticalLayout_2->addWidget(combo);
|
||||
verticalLayout_2->addItem(buttonSpacer);
|
||||
verticalLayout_2->addWidget(buttonBox);
|
||||
}
|
||||
|
||||
QLabel *pixmapLabel;
|
||||
QLabel *messageLabel;
|
||||
QComboBox* combo;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QAbstractButton *clickedButton;
|
||||
};
|
||||
|
||||
CComboInputDialog::CComboInputDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
d(new CComboInputDialogPrivate(this))
|
||||
{
|
||||
setModal(true);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
|
||||
connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
||||
connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)),
|
||||
SLOT(slotClicked(QAbstractButton*)));
|
||||
}
|
||||
|
||||
CComboInputDialog::~CComboInputDialog()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void CComboInputDialog::slotClicked(QAbstractButton *b)
|
||||
{
|
||||
d->clickedButton = b;
|
||||
}
|
||||
|
||||
QAbstractButton *CComboInputDialog::clickedButton() const
|
||||
{
|
||||
return d->clickedButton;
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CComboInputDialog::clickedStandardButton() const
|
||||
{
|
||||
if (d->clickedButton)
|
||||
return d->buttonBox->standardButton(d->clickedButton);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
QString CComboInputDialog::text() const
|
||||
{
|
||||
return d->messageLabel->text();
|
||||
}
|
||||
|
||||
void CComboInputDialog::setText(const QString &t)
|
||||
{
|
||||
d->messageLabel->setText(t);
|
||||
}
|
||||
|
||||
void CComboInputDialog::addItem(const QString& t, const QVariant & v)
|
||||
{
|
||||
d->combo->addItem(t, v);
|
||||
}
|
||||
|
||||
void CComboInputDialog::setEditable(bool b)
|
||||
{
|
||||
d->combo->setEditable(b);
|
||||
}
|
||||
|
||||
QString CComboInputDialog::value() const
|
||||
{
|
||||
return d->combo->currentText();
|
||||
}
|
||||
|
||||
void CComboInputDialog::setValue(const QString &t)
|
||||
{
|
||||
int idx = d->combo->findText(t);
|
||||
if(idx == -1)
|
||||
d->combo->setEditText(t);
|
||||
else
|
||||
d->combo->setCurrentIndex(idx);
|
||||
}
|
||||
|
||||
QVariant CComboInputDialog::data() const
|
||||
{
|
||||
return d->combo->currentData();
|
||||
}
|
||||
|
||||
void CComboInputDialog::setData(const QVariant & v)
|
||||
{
|
||||
d->combo->setCurrentIndex(d->combo->findData(v));
|
||||
}
|
||||
|
||||
QPixmap CComboInputDialog::iconPixmap() const
|
||||
{
|
||||
if (const QPixmap *p = d->pixmapLabel->pixmap())
|
||||
return QPixmap(*p);
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
void CComboInputDialog::setIconPixmap(const QPixmap &p)
|
||||
{
|
||||
d->pixmapLabel->setPixmap(p);
|
||||
d->pixmapLabel->setVisible(!p.isNull());
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButtons CComboInputDialog::standardButtons() const
|
||||
{
|
||||
return d->buttonBox->standardButtons();
|
||||
}
|
||||
|
||||
void CComboInputDialog::setStandardButtons(QDialogButtonBox::StandardButtons s)
|
||||
{
|
||||
d->buttonBox->setStandardButtons(s);
|
||||
}
|
||||
|
||||
QPushButton *CComboInputDialog::button(QDialogButtonBox::StandardButton b) const
|
||||
{
|
||||
return d->buttonBox->button(b);
|
||||
}
|
||||
|
||||
QPushButton *CComboInputDialog::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
|
||||
{
|
||||
return d->buttonBox->addButton(text, role);
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CComboInputDialog::defaultButton() const
|
||||
{
|
||||
foreach (QAbstractButton *b, d->buttonBox->buttons())
|
||||
if (QPushButton *pb = qobject_cast<QPushButton *>(b))
|
||||
if (pb->isDefault())
|
||||
return d->buttonBox->standardButton(pb);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
void CComboInputDialog::setDefaultButton(QDialogButtonBox::StandardButton s)
|
||||
{
|
||||
if (QPushButton *b = d->buttonBox->button(s)) {
|
||||
b->setDefault(true);
|
||||
b->setFocus();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef HCOMBOINPUTDIALOG_H
|
||||
#define HCOMBOINPUTDIALOG_H
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QMessageBox>
|
||||
|
||||
class CComboInputDialogPrivate;
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CComboInputDialog: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton)
|
||||
|
||||
public:
|
||||
explicit CComboInputDialog(QWidget *parent = NULL);
|
||||
virtual ~CComboInputDialog();
|
||||
|
||||
QString text() const;
|
||||
void setText(const QString &);
|
||||
|
||||
void addItem(const QString&, const QVariant & = QVariant());
|
||||
void setEditable(bool);
|
||||
|
||||
QString value() const;
|
||||
void setValue(const QString &);
|
||||
|
||||
QVariant data() const;
|
||||
void setData(const QVariant &);
|
||||
|
||||
|
||||
QDialogButtonBox::StandardButtons standardButtons() const;
|
||||
void setStandardButtons(QDialogButtonBox::StandardButtons s);
|
||||
QPushButton *button(QDialogButtonBox::StandardButton b) const;
|
||||
QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role);
|
||||
|
||||
QDialogButtonBox::StandardButton defaultButton() const;
|
||||
void setDefaultButton(QDialogButtonBox::StandardButton s);
|
||||
|
||||
// See static QMessageBox::standardPixmap()
|
||||
QPixmap iconPixmap() const;
|
||||
void setIconPixmap (const QPixmap &p);
|
||||
|
||||
// Query the result
|
||||
QAbstractButton *clickedButton() const;
|
||||
QDialogButtonBox::StandardButton clickedStandardButton() const;
|
||||
|
||||
private slots:
|
||||
void slotClicked(QAbstractButton *b);
|
||||
|
||||
private:
|
||||
CComboInputDialogPrivate *d;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // HCOMBOINPUTDIALOG_H
|
|
@ -0,0 +1,321 @@
|
|||
#include "stdafx.h"
|
||||
#include "Common.h"
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
#include <openssl/rand.h>
|
||||
#endif
|
||||
|
||||
#ifndef WIN32 // vswprintf
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
int vswprintf_l(wchar_t * _String, size_t _Count, const wchar_t * _Format, va_list _Ap)
|
||||
{
|
||||
wchar_t _Format_l[1025];
|
||||
ASSERT(wcslen(_Format) < 1024);
|
||||
wcscpy(_Format_l, _Format);
|
||||
|
||||
for(int i=0; i<wcslen(_Format_l); i++)
|
||||
{
|
||||
if(_Format_l[i] == L'%')
|
||||
{
|
||||
switch(_Format_l[i+1])
|
||||
{
|
||||
case L's': _Format_l[i+1] = 'S'; break;
|
||||
case L'S': _Format_l[i+1] = 's'; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vswprintf(_String, _Count, _Format_l, _Ap);
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Time Functions
|
||||
//
|
||||
|
||||
time_t GetTime()
|
||||
{
|
||||
QDateTime dateTime = QDateTime::currentDateTime();
|
||||
time_t time = dateTime.toTime_t(); // returns time in seconds (since 1970-01-01T00:00:00) in UTC !
|
||||
return time;
|
||||
}
|
||||
|
||||
struct SCurTick
|
||||
{
|
||||
SCurTick() {Timer.start();}
|
||||
quint64 Get(){return Timer.elapsed();}
|
||||
QElapsedTimer Timer;
|
||||
} g_CurTick;
|
||||
|
||||
quint64 GetCurTick()
|
||||
{
|
||||
return g_CurTick.Get();
|
||||
}
|
||||
|
||||
QString UnEscape(QString Text)
|
||||
{
|
||||
QString Value;
|
||||
bool bEsc = false;
|
||||
for(int i = 0; i < Text.size(); i++)
|
||||
{
|
||||
QChar Char = Text.at(i);
|
||||
if(bEsc)
|
||||
{
|
||||
switch(Char.unicode())
|
||||
{
|
||||
case L'\\': Value += L'\\'; break;
|
||||
case L'\'': Value += L'\''; break;
|
||||
case L'\"': Value += L'\"'; break;
|
||||
case L'a': Value += L'\a'; break;
|
||||
case L'b': Value += L'\b'; break;
|
||||
case L'f': Value += L'\f'; break;
|
||||
case L'n': Value += L'\n'; break;
|
||||
case L'r': Value += L'\r'; break;
|
||||
case L't': Value += L'\t'; break;
|
||||
case L'v': Value += L'\v'; break;
|
||||
default: Value += Char.unicode();break;
|
||||
}
|
||||
bEsc = false;
|
||||
}
|
||||
else if(Char == L'\\')
|
||||
bEsc = true;
|
||||
else
|
||||
Value += Char;
|
||||
}
|
||||
return Value;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Other Functions
|
||||
//
|
||||
|
||||
quint64 GetRand64()
|
||||
{
|
||||
quint64 Rand64;
|
||||
#ifdef USE_OPENSSL
|
||||
int Ret = RAND_bytes((byte*)&Rand64, sizeof(uint64));
|
||||
ASSERT(Ret == 1); // An error occurs if the PRNG has not been seeded with enough randomness to ensure an unpredictable byte sequence.
|
||||
#else
|
||||
//CryptoPP::AutoSeededRandomPool rng;
|
||||
//rng.GenerateBlock((byte*)&Rand64, sizeof(quint64));
|
||||
|
||||
Rand64 = QRandomGenerator::system()->generate64();
|
||||
#endif
|
||||
return Rand64;
|
||||
}
|
||||
|
||||
QString GetRand64Str(bool forUrl)
|
||||
{
|
||||
quint64 Rand64 = GetRand64();
|
||||
QString sRand64 = QByteArray((char*)&Rand64,sizeof(quint64)).toBase64();
|
||||
if(forUrl)
|
||||
sRand64.replace("+","-").replace("/","_");
|
||||
return sRand64.replace("=","");
|
||||
}
|
||||
|
||||
|
||||
int GetRandomInt(int iMin, int iMax)
|
||||
{
|
||||
return QRandomGenerator::system()->bounded(iMin, iMax);
|
||||
}
|
||||
|
||||
StrPair Split2(const QString& String, QString Separator, bool Back)
|
||||
{
|
||||
int Sep = Back ? String.lastIndexOf(Separator) : String.indexOf(Separator);
|
||||
if(Sep != -1)
|
||||
return qMakePair(String.left(Sep).trimmed(), String.mid(Sep+Separator.length()).trimmed());
|
||||
return qMakePair(String.trimmed(), QString());
|
||||
}
|
||||
|
||||
QStringList SplitStr(const QString& String, QString Separator)
|
||||
{
|
||||
QStringList List = String.split(Separator);
|
||||
for(int i=0; i < List.count(); i++)
|
||||
{
|
||||
List[i] = List[i].trimmed();
|
||||
if(List[i].isEmpty())
|
||||
List.removeAt(i--);
|
||||
}
|
||||
return List;
|
||||
}
|
||||
|
||||
QString FormatSize(quint64 Size, int Precision)
|
||||
{
|
||||
double Div;
|
||||
if(Size > (quint64)(Div = 1.0*1024*1024*1024*1024*1024*1024))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " EB";
|
||||
if(Size > (quint64)(Div = 1.0*1024*1024*1024*1024*1024))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " PB";
|
||||
if(Size > (quint64)(Div = 1.0*1024*1024*1024*1024))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " TB";
|
||||
if(Size > (quint64)(Div = 1.0*1024*1024*1024))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " GB";
|
||||
if(Size > (quint64)(Div = 1.0*1024*1024))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " MB";
|
||||
if(Size > (quint64)(Div = 1.0*1024))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " KB";
|
||||
return QString::number(double(Size)) + "B";
|
||||
}
|
||||
|
||||
QString FormatRate(quint64 Size, int Precision)
|
||||
{
|
||||
return FormatSize(Size, Precision) + "/s";
|
||||
}
|
||||
|
||||
QString FormatUnit(quint64 Size, int Precision)
|
||||
{
|
||||
double Div;
|
||||
if(Size > (quint64)(Div = 1.0*1000*1000*1000*1024*1000*1000))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " E";
|
||||
if(Size > (quint64)(Div = 1.0*1000*1000*1000*1000*1000))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " P";
|
||||
if(Size > (quint64)(Div = 1.0*1000*1000*1000*1000))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " T";
|
||||
if(Size > (quint64)(Div = 1.0*1000*1000*1000))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " G";
|
||||
if(Size > (quint64)(Div = 1.0*1000*1000))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " M";
|
||||
if(Size > (quint64)(Div = 1.0*1000))
|
||||
return QString::number(double(Size)/Div, 'f', Precision) + " K";
|
||||
return QString::number(double(Size));
|
||||
}
|
||||
|
||||
|
||||
QString FormatTime(quint64 Time, bool ms)
|
||||
{
|
||||
int miliseconds = 0;
|
||||
if (ms) {
|
||||
miliseconds = Time % 1000;
|
||||
Time /= 1000;
|
||||
}
|
||||
int seconds = Time % 60;
|
||||
Time /= 60;
|
||||
int minutes = Time % 60;
|
||||
Time /= 60;
|
||||
int hours = Time % 24;
|
||||
int days = Time / 24;
|
||||
if(ms && (minutes == 0) && (hours == 0) && (days == 0))
|
||||
return QString().sprintf("%02d.%04d", seconds, miliseconds);
|
||||
if((hours == 0) && (days == 0))
|
||||
return QString().sprintf("%02d:%02d", minutes, seconds);
|
||||
if (days == 0)
|
||||
return QString().sprintf("%02d:%02d:%02d", hours, minutes, seconds);
|
||||
return QString().sprintf("%dd%02d:%02d:%02d", days, hours, minutes, seconds);
|
||||
}
|
||||
|
||||
QString FormatNumber(quint64 Number)
|
||||
{
|
||||
QString String = QString::number(Number);
|
||||
for (int i = String.length() - 3; i > 0; i -= 3)
|
||||
String.insert(i, QString::fromWCharArray(L"\u202F")); // L"\u2009"
|
||||
return String;
|
||||
}
|
||||
|
||||
QString FormatAddress(quint64 Address, int length)
|
||||
{
|
||||
return "0x" + QString::number(Address, 16).rightJustified(length, '0');
|
||||
}
|
||||
|
||||
bool ReadFromDevice(QIODevice* dev, char* data, int len, int timeout)
|
||||
{
|
||||
while (dev->bytesAvailable() < len) {
|
||||
if (!dev->waitForReadyRead(timeout))
|
||||
return false;
|
||||
}
|
||||
return dev->read(data, len) == len;
|
||||
}
|
||||
|
||||
|
||||
void GrayScale (QImage& Image)
|
||||
{
|
||||
if (Image.depth () == 32)
|
||||
{
|
||||
uchar* r = (Image.bits ());
|
||||
uchar* g = (Image.bits () + 1);
|
||||
uchar* b = (Image.bits () + 2);
|
||||
|
||||
uchar* end = (Image.bits() + Image.byteCount ());
|
||||
while (r != end)
|
||||
{
|
||||
*r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3
|
||||
|
||||
r += 4;
|
||||
g += 4;
|
||||
b += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Image.colorCount (); i++)
|
||||
{
|
||||
uint r = qRed (Image.color (i));
|
||||
uint g = qGreen (Image.color (i));
|
||||
uint b = qBlue (Image.color (i));
|
||||
|
||||
uint gray = (((r + g) >> 1) + b) >> 1;
|
||||
|
||||
Image.setColor (i, qRgba (gray, gray, gray, qAlpha (Image.color (i))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QIcon MakeActionIcon(const QString& IconFile)
|
||||
{
|
||||
QImage Image(IconFile);
|
||||
QIcon Icon;
|
||||
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Normal);
|
||||
GrayScale(Image);
|
||||
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Disabled);
|
||||
return Icon;
|
||||
}
|
||||
|
||||
QAction* MakeAction(QToolBar* pParent, const QString& IconFile, const QString& Text)
|
||||
{
|
||||
QAction* pAction = new QAction(Text, pParent);
|
||||
pAction->setIcon(MakeActionIcon(IconFile));
|
||||
pParent->addAction(pAction);
|
||||
return pAction;
|
||||
}
|
||||
|
||||
QMenu* MakeMenu(QMenu* pParent, const QString& Text, const QString& IconFile)
|
||||
{
|
||||
if(!IconFile.isEmpty())
|
||||
{
|
||||
QImage Image(IconFile);
|
||||
QIcon Icon;
|
||||
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Normal);
|
||||
GrayScale(Image);
|
||||
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Disabled);
|
||||
return pParent->addMenu(Icon, Text);
|
||||
}
|
||||
return pParent->addMenu(Text);
|
||||
}
|
||||
|
||||
QAction* MakeAction(QMenu* pParent, const QString& Text, const QString& IconFile)
|
||||
{
|
||||
QAction* pAction = new QAction(Text, pParent);
|
||||
if(!IconFile.isEmpty())
|
||||
{
|
||||
QImage Image(IconFile);
|
||||
QIcon Icon;
|
||||
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Normal);
|
||||
GrayScale(Image);
|
||||
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Disabled);
|
||||
pAction->setIcon(Icon);
|
||||
}
|
||||
pParent->addAction(pAction);
|
||||
return pAction;
|
||||
}
|
||||
|
||||
QAction* MakeAction(QActionGroup* pGroup, QMenu* pParent, const QString& Text, const QVariant& Data)
|
||||
{
|
||||
QAction* pAction = new QAction(Text, pParent);
|
||||
pAction->setCheckable(true);
|
||||
pAction->setData(Data);
|
||||
pAction->setActionGroup(pGroup);
|
||||
pParent->addAction(pAction);
|
||||
return pAction;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
#ifndef WIN32
|
||||
MISCHELPERS_EXPORT int vswprintf_l(wchar_t * _String, size_t _Count, const wchar_t * _Format, va_list _Ap);
|
||||
#endif
|
||||
|
||||
MISCHELPERS_EXPORT time_t GetTime();
|
||||
MISCHELPERS_EXPORT quint64 GetCurTick();
|
||||
|
||||
|
||||
MISCHELPERS_EXPORT quint64 GetRand64();
|
||||
MISCHELPERS_EXPORT QString GetRand64Str(bool forUrl = true);
|
||||
|
||||
MISCHELPERS_EXPORT int GetRandomInt(int iMin, int iMax);
|
||||
|
||||
MISCHELPERS_EXPORT typedef QPair<QString,QString> StrPair;
|
||||
MISCHELPERS_EXPORT StrPair Split2(const QString& String, QString Separator = "=", bool Back = false);
|
||||
MISCHELPERS_EXPORT QStringList SplitStr(const QString& String, QString Separator);
|
||||
|
||||
MISCHELPERS_EXPORT QString UnEscape(QString Text);
|
||||
|
||||
MISCHELPERS_EXPORT QString FormatSize(quint64 Size, int Precision = 2);
|
||||
__inline QString FormatSizeEx(quint64 Size, bool bEx) { return bEx && (Size == 0) ? QString() : FormatSize(Size); }
|
||||
MISCHELPERS_EXPORT QString FormatRate(quint64 Size, int Precision = 2);
|
||||
__inline QString FormatRateEx(quint64 Size, bool bEx) { return bEx && (Size == 0) ? QString() : FormatRate(Size); }
|
||||
MISCHELPERS_EXPORT QString FormatUnit(quint64 Size, int Precision = 0);
|
||||
MISCHELPERS_EXPORT QString FormatTime(quint64 Time, bool ms = false);
|
||||
MISCHELPERS_EXPORT QString FormatNumber(quint64 Number);
|
||||
__inline QString FormatNumberEx(quint64 Number, bool bEx) { return bEx && (Number == 0) ? QString() : FormatNumber(Number); }
|
||||
MISCHELPERS_EXPORT QString FormatAddress(quint64 Address, int length = 16);
|
||||
|
||||
|
||||
inline bool operator < (const QHostAddress &key1, const QHostAddress &key2)
|
||||
{
|
||||
// Note: toIPv6Address also works for IPv4 addresses
|
||||
Q_IPV6ADDR ip1 = key1.toIPv6Address();
|
||||
Q_IPV6ADDR ip2 = key2.toIPv6Address();
|
||||
return memcmp(&ip1, &ip2, sizeof(Q_IPV6ADDR)) < 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QVariantList toVariantList( const QList<T> &list )
|
||||
{
|
||||
QVariantList newList;
|
||||
foreach( const T &item, list )
|
||||
newList << item;
|
||||
|
||||
return newList;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QList<T> reversed( const QList<T> & in ) {
|
||||
QList<T> result;
|
||||
result.reserve( in.size() ); // reserve is new in Qt 4.7
|
||||
std::reverse_copy( in.begin(), in.end(), std::back_inserter( result ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class CScoped
|
||||
{
|
||||
public:
|
||||
CScoped(T* Val = NULL) {m_Val = Val;}
|
||||
~CScoped() {delete m_Val;}
|
||||
|
||||
CScoped<T>& operator=(const CScoped<T>& Scoped) {ASSERT(0); return *this;} // copying is explicitly forbidden
|
||||
CScoped<T>& operator=(T* Val) {ASSERT(!m_Val); m_Val = Val; return *this;}
|
||||
|
||||
inline T* Val() const {return m_Val;}
|
||||
inline T* &Val() {return m_Val;}
|
||||
inline T* Detache() {T* Val = m_Val; m_Val = NULL; return Val;}
|
||||
inline T* operator->() const {return m_Val;}
|
||||
inline T& operator*() const {return *m_Val;}
|
||||
inline operator T*() const {return m_Val;}
|
||||
|
||||
private:
|
||||
T* m_Val;
|
||||
};
|
||||
|
||||
MISCHELPERS_EXPORT bool ReadFromDevice(QIODevice* dev, char* data, int len, int timeout = 5000);
|
||||
|
||||
|
||||
MISCHELPERS_EXPORT void GrayScale (QImage& Image);
|
||||
|
||||
MISCHELPERS_EXPORT QIcon MakeActionIcon(const QString& IconFile);
|
||||
MISCHELPERS_EXPORT QAction* MakeAction(QToolBar* pParent, const QString& IconFile, const QString& Text = "");
|
||||
MISCHELPERS_EXPORT QMenu* MakeMenu(QMenu* pParent, const QString& Text, const QString& IconFile = "");
|
||||
MISCHELPERS_EXPORT QAction* MakeAction(QMenu* pParent, const QString& Text, const QString& IconFile = "");
|
||||
MISCHELPERS_EXPORT QAction* MakeAction(QActionGroup* pGroup, QMenu* pParent, const QString& Text, const QVariant& Data);
|
||||
|
|
@ -0,0 +1,391 @@
|
|||
#include "stdafx.h"
|
||||
#include "DebugHelpers.h"
|
||||
#include "Common.h"
|
||||
#include <QDebug>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
bool IsDebuggerAttached()
|
||||
{
|
||||
bool isDebuggerPresent = false; // Note: on linux change edit the value in debgger to indicate precense
|
||||
#ifdef WIN32
|
||||
if (IsDebuggerPresent())
|
||||
return true;
|
||||
#endif
|
||||
return isDebuggerPresent;
|
||||
}
|
||||
|
||||
void WaitForDebugger()
|
||||
{
|
||||
while (!IsDebuggerAttached())
|
||||
QThread::msleep(500);
|
||||
}
|
||||
|
||||
|
||||
#if defined(_DEBUG) || defined(_TRACE)
|
||||
|
||||
#ifdef WIN32
|
||||
bool g_assert_active = IsDebuggerPresent();
|
||||
#else
|
||||
bool g_assert_active = true;
|
||||
#endif
|
||||
|
||||
void Assert(bool test)
|
||||
{
|
||||
if(!test && g_assert_active)
|
||||
_CrtDbgBreak();
|
||||
}
|
||||
|
||||
void CTracer::operator()(const QString &sLine) const
|
||||
{
|
||||
qDebug() << sLine;
|
||||
}
|
||||
|
||||
void CTracer::operator()(const wchar_t *sLine, ...) const
|
||||
{
|
||||
const size_t bufferSize = 10241;
|
||||
wchar_t bufferline[bufferSize];
|
||||
|
||||
va_list argptr;
|
||||
va_start(argptr, sLine);
|
||||
#ifndef WIN32
|
||||
if (vswprintf_l(bufferline, bufferSize, sLine, argptr) == -1)
|
||||
#else
|
||||
if (vswprintf(bufferline, bufferSize, sLine, argptr) == -1)
|
||||
#endif
|
||||
bufferline[bufferSize - 1] = L'\0';
|
||||
va_end(argptr);
|
||||
|
||||
QString sBufferLine = QString::fromWCharArray(bufferline);
|
||||
qDebug() << sBufferLine;
|
||||
}
|
||||
|
||||
void CTracer::operator()(const char *sLine, ...) const
|
||||
{
|
||||
const size_t bufferSize = 10241;
|
||||
char bufferline[bufferSize];
|
||||
|
||||
va_list argptr;
|
||||
va_start(argptr, sLine);
|
||||
if (vsprintf(bufferline, sLine, argptr) == -1)
|
||||
bufferline[bufferSize - 1] = L'\0';
|
||||
va_end(argptr);
|
||||
|
||||
QString sBufferLine = bufferline;
|
||||
qDebug() << sBufferLine;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tracers
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CMemTracer memTracer;
|
||||
|
||||
void CMemTracer::DumpTrace()
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
for(map<string,int>::iterator I = m_MemoryTrace.begin(); I != m_MemoryTrace.end(); I++)
|
||||
{
|
||||
|
||||
map<string,int>::iterator J = m_MemoryTrace2.find(I->first);
|
||||
if(J != m_MemoryTrace2.end())
|
||||
TRACE(L"MEMORY TRACE: Object '%S' has %d (%d) instances.",I->first.c_str(),I->second, J->second);
|
||||
else
|
||||
TRACE(L"MEMORY TRACE: Object '%S' has %d instances.",I->first.c_str(),I->second);
|
||||
}
|
||||
}
|
||||
|
||||
void CMemTracer::TraceAlloc(string Name)
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
m_MemoryTrace[Name] += 1;
|
||||
}
|
||||
|
||||
void CMemTracer::TraceFree(string Name)
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
m_MemoryTrace[Name] -= 1;
|
||||
|
||||
//if(m_MemoryTrace2[Name] > 0)
|
||||
if(m_MemoryTrace2.find(Name) != m_MemoryTrace2.end())
|
||||
m_MemoryTrace2[Name] -= 1;
|
||||
}
|
||||
|
||||
void CMemTracer::TracePre(string Name)
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
m_MemoryTrace2[Name] += 1;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
CCpuTracer cpuTracer;
|
||||
|
||||
void CCpuTracer::DumpTrace()
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
for(map<string,SCycles>::iterator I = m_CpuUsageTrace.begin(); I != m_CpuUsageTrace.end(); I++)
|
||||
TRACE(L"CPU TRACE: Prozedure '%S' needed %f seconds.",I->first.c_str(),(double)I->second.Total/1000000.0);
|
||||
}
|
||||
|
||||
void CCpuTracer::ResetTrace()
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
m_CpuUsageTrace.clear();
|
||||
}
|
||||
|
||||
void CCpuTracer::TraceStart(string Name)
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
m_CpuUsageTrace[Name].Counting = GetCurCycle();
|
||||
}
|
||||
|
||||
void CCpuTracer::TraceStop(string Name)
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
m_CpuUsageTrace[Name].Total += GetCurCycle() - m_CpuUsageTrace[Name].Counting;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
CLockTracer lockTracer;
|
||||
|
||||
void CLockTracer::DumpTrace()
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
for(map<string,SLocks>::iterator I = m_LockTrace.begin(); I != m_LockTrace.end(); I++)
|
||||
TRACE(L"LOCK TRACE: Lock '%S' has %d Locks for %f seconds.",I->first.c_str(),I->second.LockCount, (double)(GetCurCycle()/1000 - I->second.LockTime) / 1000);
|
||||
}
|
||||
|
||||
void CLockTracer::TraceLock(string Name, int op)
|
||||
{
|
||||
QMutexLocker Locker(&m_Locker);
|
||||
SLocks &Locks = m_LockTrace[Name];
|
||||
if(Locks.LockCount == 0)
|
||||
Locks.LockTime = GetCurCycle()/1000;
|
||||
Locks.LockCount += op;
|
||||
if(Locks.LockCount == 0)
|
||||
Locks.LockTime = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
#ifdef WIN32
|
||||
#include <dbghelp.h>
|
||||
|
||||
typedef BOOL (__stdcall *tMDWD)(
|
||||
IN HANDLE hProcess,
|
||||
IN DWORD ProcessId,
|
||||
IN HANDLE hFile,
|
||||
IN MINIDUMP_TYPE DumpType,
|
||||
IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
|
||||
IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
|
||||
IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
|
||||
);
|
||||
|
||||
|
||||
static tMDWD s_pMDWD;
|
||||
static HMODULE s_hDbgHelpMod;
|
||||
static MINIDUMP_TYPE s_dumpTyp = MiniDumpNormal; // MiniDumpWithDataSegs or MiniDumpWithFullMemory
|
||||
static wchar_t s_szMiniDumpName[64];
|
||||
|
||||
static LONG __stdcall MyCrashHandlerExceptionFilter(EXCEPTION_POINTERS* pEx)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
if (pEx->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
|
||||
{
|
||||
// be sure that we have enought space...
|
||||
static char MyStack[1024*128];
|
||||
// it assumes that DS and SS are the same!!! (this is the case for Win32)
|
||||
// change the stack only if the selectors are the same (this is the case for Win32)
|
||||
//__asm push offset MyStack[1024*128];
|
||||
//__asm pop esp;
|
||||
__asm mov eax,offset MyStack[1024*128];
|
||||
__asm mov esp,eax;
|
||||
}
|
||||
#endif
|
||||
bool bSuccess = false;
|
||||
|
||||
wchar_t szMiniDumpFileName[128];
|
||||
wsprintf(szMiniDumpFileName, L"%s %s.dmp", s_szMiniDumpName, QDateTime::currentDateTime().toString("dd.MM.yyyy hh-mm-ss,zzz").replace(QRegExp("[:*?<>|\"\\/]"), "_").toStdWString().c_str());
|
||||
|
||||
wchar_t szMiniDumpPath[MAX_PATH] = { 0 };
|
||||
|
||||
HANDLE hFile = CreateFile(szMiniDumpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
GetCurrentDirectory(MAX_PATH, szMiniDumpPath);
|
||||
else
|
||||
{
|
||||
GetTempPath(MAX_PATH, szMiniDumpPath);
|
||||
|
||||
wchar_t szMiniDumpFilePath[MAX_PATH] = { 0 };
|
||||
wsprintf(szMiniDumpFilePath, L"%s\\%s.dmp", szMiniDumpPath, szMiniDumpFileName);
|
||||
hFile = CreateFile(szMiniDumpFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
}
|
||||
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
MINIDUMP_EXCEPTION_INFORMATION stMDEI;
|
||||
stMDEI.ThreadId = GetCurrentThreadId();
|
||||
stMDEI.ExceptionPointers = pEx;
|
||||
stMDEI.ClientPointers = TRUE;
|
||||
// try to create an miniDump:
|
||||
if (s_pMDWD(GetCurrentProcess(), GetCurrentProcessId(), hFile, s_dumpTyp, &stMDEI, NULL, NULL))
|
||||
{
|
||||
bSuccess = true;
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
wchar_t szMiniDumpMessage[256];
|
||||
if (!bSuccess)
|
||||
wsprintf(szMiniDumpMessage, L"%s crashed!\r\nCrashdump creation failed.", s_szMiniDumpName);
|
||||
else
|
||||
wsprintf(szMiniDumpMessage, L"%s crashed!\r\nCrashdump saved to \"%s\".\r\nPlease report the crash and attach the file \"%s\".", s_szMiniDumpName, szMiniDumpPath, szMiniDumpFileName);
|
||||
MessageBox(NULL, szMiniDumpMessage, s_szMiniDumpName, MB_OK | MB_ICONERROR);
|
||||
|
||||
// or return one of the following:
|
||||
// - EXCEPTION_CONTINUE_SEARCH
|
||||
// - EXCEPTION_CONTINUE_EXECUTION
|
||||
// - EXCEPTION_EXECUTE_HANDLER
|
||||
return EXCEPTION_CONTINUE_SEARCH; // this will trigger the "normal" OS error-dialog
|
||||
}
|
||||
|
||||
void InitMiniDumpWriter(const wchar_t* Name)
|
||||
{
|
||||
if (s_hDbgHelpMod != NULL)
|
||||
return;
|
||||
|
||||
ASSERT(wcslen(Name) < ARRSIZE(s_szMiniDumpName));
|
||||
wcscpy(s_szMiniDumpName, Name);
|
||||
|
||||
// Initialize the member, so we do not load the dll after the exception has occured
|
||||
// which might be not possible anymore...
|
||||
s_hDbgHelpMod = LoadLibrary(L"dbghelp.dll");
|
||||
if (s_hDbgHelpMod != NULL)
|
||||
s_pMDWD = (tMDWD) GetProcAddress(s_hDbgHelpMod, "MiniDumpWriteDump");
|
||||
|
||||
// Register Unhandled Exception-Filter:
|
||||
SetUnhandledExceptionFilter(MyCrashHandlerExceptionFilter);
|
||||
|
||||
// Additional call "PreventSetUnhandledExceptionFilter"...
|
||||
// See also: "SetUnhandledExceptionFilter" and VC8 (and later)
|
||||
// http://blog.kalmbachnet.de/?postid=75
|
||||
}
|
||||
|
||||
|
||||
quint64 GetCurCycle()
|
||||
{
|
||||
quint64 freq, now;
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&now);
|
||||
quint64 dwNow = ((now * 1000000) / freq) & 0xffffffff;
|
||||
return dwNow; // returns time since system start in us
|
||||
}
|
||||
|
||||
|
||||
#elif !defined(__APPLE__)
|
||||
#include <stdio.h>
|
||||
#include <execinfo.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static wchar_t s_szMiniDumpName[64];
|
||||
|
||||
/* This structure mirrors the one found in /usr/include/asm/ucontext.h */
|
||||
typedef struct _sig_ucontext {
|
||||
unsigned long uc_flags;
|
||||
struct ucontext *uc_link;
|
||||
stack_t uc_stack;
|
||||
struct sigcontext uc_mcontext;
|
||||
sigset_t uc_sigmask;
|
||||
} sig_ucontext_t;
|
||||
|
||||
void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
|
||||
{
|
||||
void * array[50];
|
||||
void * caller_address;
|
||||
char ** messages;
|
||||
int size, i;
|
||||
sig_ucontext_t * uc;
|
||||
|
||||
uc = (sig_ucontext_t *)ucontext;
|
||||
|
||||
/* Get the address at the time the signal was raised */
|
||||
#if defined(__i386__) // gcc specific
|
||||
caller_address = (void *) uc->uc_mcontext.eip; // EIP: x86 specific
|
||||
#elif defined(__x86_64__) // gcc specific
|
||||
caller_address = (void *) uc->uc_mcontext.rip; // RIP: x86_64 specific
|
||||
#else
|
||||
#error Unsupported architecture. // TO-DO: Add support for other arch.
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "signal %d (%s), address is %p from %p\n",
|
||||
sig_num, strsignal(sig_num), info->si_addr,
|
||||
(void *)caller_address);
|
||||
|
||||
size = backtrace(array, 50);
|
||||
|
||||
/* overwrite sigaction with caller's address */
|
||||
array[1] = caller_address;
|
||||
|
||||
messages = backtrace_symbols(array, size);
|
||||
|
||||
char szMiniDumpFileName[128];
|
||||
sprintf(szMiniDumpFileName, "%S_%s.log", s_szMiniDumpName, QDateTime::currentDateTime().toString("dd.MM.yyyy_hh-mm-ss,zzz").replace(QRegExp("[:*?<>|\"\\/]"), "_").toStdString().c_str());
|
||||
|
||||
FILE* file = fopen(szMiniDumpFileName, "wb");
|
||||
|
||||
/* skip first stack frame (points here) */
|
||||
for (i = 1; i < size && messages != NULL; ++i)
|
||||
{
|
||||
fprintf(stderr, "[bt]: (%d) %s\n", i, messages[i]);
|
||||
fprintf(file, "[bt]: (%d) %s\n", i, messages[i]);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
free(messages);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void InstallSigAction(int sig)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
sigact.sa_sigaction = crit_err_hdlr;
|
||||
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
|
||||
if (sigaction(sig, &sigact, (struct sigaction *)NULL) != 0)
|
||||
{
|
||||
fprintf(stderr, "error setting signal handler for %d (%s)\n", sig, strsignal(sig));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void InitMiniDumpWriter(const wchar_t* Name)
|
||||
{
|
||||
ASSERT(wcslen(Name) < ARRSIZE(s_szMiniDumpName));
|
||||
wcscpy(s_szMiniDumpName, Name);
|
||||
|
||||
InstallSigAction(SIGABRT);
|
||||
InstallSigAction(SIGSEGV);
|
||||
}
|
||||
|
||||
quint64 GetCurCycle()
|
||||
{
|
||||
return GetCurTick()*1000; // ToDo
|
||||
}
|
||||
|
||||
#else
|
||||
void InitMiniDumpWriter(const wchar_t* Name)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,173 @@
|
|||
#pragma once
|
||||
|
||||
//#define _TRACE
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
MISCHELPERS_EXPORT bool IsDebuggerAttached();
|
||||
|
||||
MISCHELPERS_EXPORT void WaitForDebugger();
|
||||
|
||||
#if defined(_DEBUG) || defined(_TRACE)
|
||||
|
||||
|
||||
MISCHELPERS_EXPORT void Assert(bool test);
|
||||
|
||||
#define TRACE CTracer()
|
||||
#define ASSERT(x) Assert(x)
|
||||
#define VERIFY(f) ASSERT(f)
|
||||
#define DEBUG_ONLY(f) (f)
|
||||
|
||||
MISCHELPERS_EXPORT extern bool g_assert_active;
|
||||
|
||||
class MISCHELPERS_EXPORT CTracer
|
||||
{
|
||||
public:
|
||||
void operator()(const QString &sLine) const;
|
||||
void operator()(const wchar_t *sLine, ...) const;
|
||||
void operator()(const char *sLine, ...) const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tracers
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class MISCHELPERS_EXPORT CMemTracer
|
||||
{
|
||||
public:
|
||||
//CMemTracer();
|
||||
//~CMemTracer();
|
||||
|
||||
void DumpTrace();
|
||||
|
||||
void TraceAlloc(string Name);
|
||||
void TraceFree(string Name);
|
||||
void TracePre(string Name);
|
||||
|
||||
|
||||
private:
|
||||
QMutex m_Locker;
|
||||
map<string,int> m_MemoryTrace;
|
||||
map<string,int> m_MemoryTrace2;
|
||||
};
|
||||
|
||||
MISCHELPERS_EXPORT extern CMemTracer memTracer;
|
||||
|
||||
#define TRACE_ALLOC(x) memTracer.TraceAlloc(x);
|
||||
#define TRACE_FREE(x) memTracer.TraceFree(x);
|
||||
#define TRACE_PRE_FREE(x) memTracer.TracePre(x);
|
||||
#define TRACE_MEMORY memTracer.DumpTrace();
|
||||
|
||||
class MISCHELPERS_EXPORT CCpuTracer
|
||||
{
|
||||
public:
|
||||
//CCpuTracer();
|
||||
//~CCpuTracer();
|
||||
|
||||
void DumpTrace();
|
||||
void ResetTrace();
|
||||
|
||||
void TraceStart(string Name);
|
||||
void TraceStop(string Name);
|
||||
|
||||
private:
|
||||
struct SCycles
|
||||
{
|
||||
SCycles()
|
||||
{
|
||||
Counting = 0;
|
||||
Total = 0;
|
||||
}
|
||||
quint64 Counting;
|
||||
quint64 Total;
|
||||
};
|
||||
QMutex m_Locker;
|
||||
map<string,SCycles> m_CpuUsageTrace;
|
||||
};
|
||||
|
||||
MISCHELPERS_EXPORT extern CCpuTracer cpuTracer;
|
||||
|
||||
#define TRACE_RESET cpuTracer.ResetTrace();
|
||||
#define TRACE_START(x) cpuTracer.TraceStart(x);
|
||||
#define TRACE_STOP(x) cpuTracer.TraceStop(x);
|
||||
#define TRACE_CPU cpuTracer.DumpTrace();
|
||||
|
||||
|
||||
class MISCHELPERS_EXPORT CLockTracer
|
||||
{
|
||||
public:
|
||||
//CLockTracer();
|
||||
//~CLockTracer();
|
||||
|
||||
void DumpTrace();
|
||||
|
||||
void TraceLock(string Name, int op);
|
||||
|
||||
private:
|
||||
QMutex m_Locker;
|
||||
struct SLocks
|
||||
{
|
||||
SLocks()
|
||||
{
|
||||
LockTime = 0;
|
||||
LockCount = 0;
|
||||
}
|
||||
time_t LockTime;
|
||||
int LockCount;
|
||||
};
|
||||
map<string,SLocks> m_LockTrace;
|
||||
};
|
||||
|
||||
MISCHELPERS_EXPORT extern CLockTracer lockTracer;
|
||||
|
||||
#define TRACE_LOCK(x) lockTracer.TraceLock(x,1);
|
||||
#define TRACE_UNLOCK(x)lockTracer.TraceLock(x,-1);
|
||||
#define TRACE_LOCKING lockTracer.DumpTrace();
|
||||
|
||||
class MISCHELPERS_EXPORT CLockerTrace
|
||||
{
|
||||
public:
|
||||
CLockerTrace(string Name)
|
||||
{
|
||||
m_Name = Name;
|
||||
lockTracer.TraceLock(m_Name,1);
|
||||
}
|
||||
~CLockerTrace()
|
||||
{
|
||||
lockTracer.TraceLock(m_Name,-1);
|
||||
}
|
||||
|
||||
private:
|
||||
string m_Name;
|
||||
};
|
||||
|
||||
#define TRACE_LOCKER(x)CLockerTrace LockTrace(x)
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
//#define X_ASSERT(x) if(!(x)) throw "Assertion failed in: " __FUNCTION__ "; File:" __FILE__ "; Line:" STR(__LINE__) ";";
|
||||
|
||||
#define TRACE
|
||||
#define ASSERT(x)
|
||||
#define VERIFY(f) (f)
|
||||
#define DEBUG_ONLY(f)
|
||||
|
||||
#define TRACE_ALLOC(x)
|
||||
#define TRACE_FREE(x)
|
||||
#define TRACE_MEMORY
|
||||
|
||||
#define TRACE_RESET
|
||||
#define TRACE_START(x)
|
||||
#define TRACE_STOP(x)
|
||||
#define TRACE_CPUUSAGE
|
||||
#define TRACE_CPU
|
||||
|
||||
#define TRACE_LOCK(x)
|
||||
#define TRACE_UNLOCK(x)
|
||||
#define TRACE_LOCKING
|
||||
#define TRACE_LOCKER(x)
|
||||
#endif
|
||||
|
||||
MISCHELPERS_EXPORT void InitMiniDumpWriter(const wchar_t* Name);
|
||||
MISCHELPERS_EXPORT quint64 GetCurCycle();
|
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CExitDialog : public QDialog
|
||||
{
|
||||
public:
|
||||
CExitDialog(const QString& Prompt, QWidget* parent = 0)
|
||||
: QDialog(parent)
|
||||
{
|
||||
m_pMainLayout = new QGridLayout(this);
|
||||
|
||||
QLabel* pLabel = new QLabel(Prompt);
|
||||
m_pMainLayout->addWidget(pLabel, 0, 0, 1, 1);
|
||||
|
||||
m_pButtonBox = new QDialogButtonBox();
|
||||
m_pButtonBox->setOrientation(Qt::Horizontal);
|
||||
m_pButtonBox->setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::No);
|
||||
m_pMainLayout->addWidget(m_pButtonBox, 2, 0, 1, 1);
|
||||
|
||||
connect(m_pButtonBox,SIGNAL(accepted()),this,SLOT(accept()));
|
||||
connect(m_pButtonBox,SIGNAL(rejected()),this,SLOT(reject()));
|
||||
|
||||
m_TimerId = startTimer(1000);
|
||||
m_CountDown = 15;
|
||||
}
|
||||
~CExitDialog()
|
||||
{
|
||||
killTimer(m_TimerId);
|
||||
}
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if (e->timerId() != m_TimerId)
|
||||
{
|
||||
QDialog::timerEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_CountDown != 0)
|
||||
{
|
||||
m_CountDown--;
|
||||
m_pButtonBox->button(QDialogButtonBox::Yes)->setText(tr("Yes (%1)").arg(m_CountDown));
|
||||
if(m_CountDown == 0)
|
||||
accept();
|
||||
}
|
||||
}
|
||||
|
||||
void reject()
|
||||
{
|
||||
hide();
|
||||
}
|
||||
|
||||
void closeEvent(QCloseEvent *e)
|
||||
{
|
||||
hide();
|
||||
e->ignore();
|
||||
}
|
||||
|
||||
int m_TimerId;
|
||||
int m_CountDown;
|
||||
|
||||
QGridLayout* m_pMainLayout;
|
||||
QDialogButtonBox * m_pButtonBox;
|
||||
};
|
|
@ -0,0 +1,125 @@
|
|||
#include "stdafx.h"
|
||||
#include "Finder.h"
|
||||
|
||||
QWidget* CFinder::AddFinder(QWidget* pList, QObject* pFilterTarget, bool HighLightOption, CFinder** ppFinder)
|
||||
{
|
||||
QWidget* pWidget = new QWidget();
|
||||
QVBoxLayout* pLayout = new QVBoxLayout();
|
||||
pLayout->setMargin(0);
|
||||
pWidget->setLayout(pLayout);
|
||||
|
||||
pLayout->addWidget(pList);
|
||||
CFinder* pFinder = new CFinder(pFilterTarget, pWidget, HighLightOption);
|
||||
pLayout->addWidget(pFinder);
|
||||
|
||||
if (ppFinder)
|
||||
*ppFinder = pFinder;
|
||||
return pWidget;
|
||||
}
|
||||
|
||||
CFinder::CFinder(QObject* pFilterTarget, QWidget *parent, bool HighLightOption)
|
||||
:QWidget(parent)
|
||||
{
|
||||
m_pSearchLayout = new QHBoxLayout();
|
||||
m_pSearchLayout->setMargin(3);
|
||||
m_pSearchLayout->setSpacing(3);
|
||||
m_pSearchLayout->setAlignment(Qt::AlignLeft);
|
||||
|
||||
m_pSearch = new QLineEdit();
|
||||
m_pSearch->setMinimumWidth(150);
|
||||
m_pSearch->setMaximumWidth(350);
|
||||
m_pSearchLayout->addWidget(m_pSearch);
|
||||
QObject::connect(m_pSearch, SIGNAL(textChanged(QString)), this, SLOT(OnUpdate()));
|
||||
//QObject::connect(m_pSearch, SIGNAL(returnPressed()), this, SLOT(_q_next()));
|
||||
|
||||
m_pCaseSensitive = new QCheckBox(tr("Case Sensitive"));
|
||||
m_pSearchLayout->addWidget(m_pCaseSensitive);
|
||||
connect(m_pCaseSensitive, SIGNAL(stateChanged(int)), this, SLOT(OnUpdate()));
|
||||
|
||||
m_pRegExp = new QCheckBox(tr("RegExp"));
|
||||
m_pSearchLayout->addWidget(m_pRegExp);
|
||||
connect(m_pRegExp, SIGNAL(stateChanged(int)), this, SLOT(OnUpdate()));
|
||||
|
||||
m_pColumn = new QComboBox();
|
||||
m_pSearchLayout->addWidget(m_pColumn);
|
||||
connect(m_pColumn, SIGNAL(currentIndexChanged(int)), this, SLOT(OnUpdate()));
|
||||
m_pColumn->setVisible(false);
|
||||
|
||||
if (HighLightOption)
|
||||
{
|
||||
m_pHighLight = new QCheckBox(tr("Highlight"));
|
||||
m_pSearchLayout->addWidget(m_pHighLight);
|
||||
connect(m_pHighLight, SIGNAL(stateChanged(int)), this, SLOT(OnUpdate()));
|
||||
}
|
||||
else
|
||||
m_pHighLight = NULL;
|
||||
|
||||
QToolButton* pClose = new QToolButton(this);
|
||||
pClose->setIcon(QIcon(":/close.png"));
|
||||
pClose->setAutoRaise(true);
|
||||
pClose->setText(tr("Close"));
|
||||
m_pSearchLayout->addWidget(pClose);
|
||||
QObject::connect(pClose, SIGNAL(clicked()), this, SLOT(Close()));
|
||||
|
||||
QWidget* pSpacer = new QWidget();
|
||||
pSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_pSearchLayout->addWidget(pSpacer);
|
||||
|
||||
setLayout(m_pSearchLayout);
|
||||
|
||||
setMaximumHeight(30);
|
||||
|
||||
hide();
|
||||
|
||||
if (parent)
|
||||
{
|
||||
QAction* pFind = new QAction(tr("&Find ..."), parent);
|
||||
pFind->setShortcut(QKeySequence::Find);
|
||||
pFind->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
parent->addAction(pFind);
|
||||
QObject::connect(pFind, SIGNAL(triggered()), this, SLOT(Open()));
|
||||
}
|
||||
|
||||
m_pSortProxy = qobject_cast<QSortFilterProxyModel*>(pFilterTarget);
|
||||
if (pFilterTarget)
|
||||
QObject::connect(this, SIGNAL(SetFilter(const QRegExp&, bool, int)), pFilterTarget, SLOT(SetFilter(const QRegExp&, bool, int)));
|
||||
}
|
||||
|
||||
CFinder::~CFinder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CFinder::Open()
|
||||
{
|
||||
if (m_pSortProxy && m_pColumn->count() == 0)
|
||||
{
|
||||
m_pColumn->addItem(tr("All columns"), -1);
|
||||
for (int i = 0; i < m_pSortProxy->columnCount(); i++)
|
||||
m_pColumn->addItem(m_pSortProxy->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(), i);
|
||||
m_pColumn->setVisible(true);
|
||||
}
|
||||
|
||||
show();
|
||||
m_pSearch->setFocus(Qt::OtherFocusReason);
|
||||
m_pSearch->selectAll();
|
||||
OnUpdate();
|
||||
}
|
||||
|
||||
QRegExp CFinder::GetRegExp() const
|
||||
{
|
||||
if (!isVisible())
|
||||
return QRegExp();
|
||||
return QRegExp(m_pSearch->text(), m_pCaseSensitive->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive, m_pRegExp->isChecked() ? QRegExp::RegExp : QRegExp::FixedString);
|
||||
}
|
||||
|
||||
void CFinder::OnUpdate()
|
||||
{
|
||||
emit SetFilter(GetRegExp(), GetHighLight(), GetColumn());
|
||||
}
|
||||
|
||||
void CFinder::Close()
|
||||
{
|
||||
emit SetFilter(QRegExp());
|
||||
hide();
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CFinder: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CFinder(QObject* pFilterTarget, QWidget *parent = NULL, bool HighLightOption = true);
|
||||
~CFinder();
|
||||
|
||||
static QWidget* AddFinder(QWidget* pList, QObject* pFilterTarget, bool HighLightOption = true, CFinder** ppFinder = NULL);
|
||||
|
||||
QRegExp GetRegExp() const;
|
||||
bool GetHighLight() const { return m_pHighLight ? m_pHighLight->isChecked() : false; }
|
||||
int GetColumn() const { return m_pColumn->currentData().toInt(); }
|
||||
|
||||
signals:
|
||||
void SetFilter(const QRegExp& Exp, bool bHighLight = false, int Column = -1);
|
||||
|
||||
public slots:
|
||||
void Open();
|
||||
void OnUpdate();
|
||||
void Close();
|
||||
|
||||
private:
|
||||
|
||||
QHBoxLayout* m_pSearchLayout;
|
||||
|
||||
QLineEdit* m_pSearch;
|
||||
QCheckBox* m_pCaseSensitive;
|
||||
QCheckBox* m_pRegExp;
|
||||
QComboBox* m_pColumn;
|
||||
QCheckBox* m_pHighLight;
|
||||
|
||||
QSortFilterProxyModel* m_pSortProxy;
|
||||
};
|
|
@ -0,0 +1,87 @@
|
|||
#pragma once
|
||||
|
||||
#define ERROR_UNDEFINED (1)
|
||||
#define ERROR_CONFIRM (2)
|
||||
#define ERROR_INTERNAL (3)
|
||||
#define ERROR_PARAMS (4)
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CFlexError
|
||||
{
|
||||
public:
|
||||
CFlexError()
|
||||
{
|
||||
m = NULL;
|
||||
}
|
||||
CFlexError(const QString& Error, long Status = ERROR_UNDEFINED) : CFlexError()
|
||||
{
|
||||
Attach(MkError(Error, Status));
|
||||
}
|
||||
CFlexError(long Status) : CFlexError(QObject::tr("Error"), Status)
|
||||
{
|
||||
}
|
||||
CFlexError(const CFlexError& other) : CFlexError()
|
||||
{
|
||||
if(other.m != NULL)
|
||||
Attach((SFlexError*)other.m);
|
||||
}
|
||||
~CFlexError()
|
||||
{
|
||||
Detach();
|
||||
}
|
||||
|
||||
CFlexError& operator=(const CFlexError& Array)
|
||||
{
|
||||
Attach(Array.m);
|
||||
return *this;
|
||||
}
|
||||
|
||||
__inline bool IsError() const { return m != NULL; }
|
||||
__inline long GetStatus() const { return m ? m->Status : 0; }
|
||||
__inline QString GetText() const { return m ? m->Error: ""; }
|
||||
|
||||
operator bool() const {return !IsError();}
|
||||
|
||||
private:
|
||||
struct SFlexError
|
||||
{
|
||||
QString Error;
|
||||
long Status;
|
||||
|
||||
mutable atomic<int> aRefCnt;
|
||||
} *m;
|
||||
|
||||
SFlexError* MkError(const QString& Error, long Status)
|
||||
{
|
||||
SFlexError* p = new SFlexError();
|
||||
p->Error = Error;
|
||||
p->Status = Status;
|
||||
return p;
|
||||
}
|
||||
|
||||
void Attach(SFlexError* p)
|
||||
{
|
||||
Detach();
|
||||
|
||||
if (p != NULL)
|
||||
{
|
||||
p->aRefCnt.fetch_add(1);
|
||||
m = p;
|
||||
}
|
||||
}
|
||||
|
||||
void Detach()
|
||||
{
|
||||
if (m != NULL)
|
||||
{
|
||||
if (m->aRefCnt.fetch_sub(1) == 1)
|
||||
delete m;
|
||||
m = NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef CFlexError STATUS;
|
||||
#define OK CFlexError()
|
||||
#define ERR CFlexError
|
|
@ -0,0 +1,223 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "FlowLayout.h"
|
||||
|
||||
//! [1]
|
||||
QFlowLayout::QFlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
|
||||
: QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
|
||||
{
|
||||
setContentsMargins(margin, margin, margin, margin);
|
||||
}
|
||||
|
||||
QFlowLayout::QFlowLayout(int margin, int hSpacing, int vSpacing)
|
||||
: m_hSpace(hSpacing), m_vSpace(vSpacing)
|
||||
{
|
||||
setContentsMargins(margin, margin, margin, margin);
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
QFlowLayout::~QFlowLayout()
|
||||
{
|
||||
QLayoutItem *item;
|
||||
while ((item = takeAt(0)))
|
||||
delete item;
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
void QFlowLayout::addItem(QLayoutItem *item)
|
||||
{
|
||||
itemList.append(item);
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
int QFlowLayout::horizontalSpacing() const
|
||||
{
|
||||
if (m_hSpace >= 0) {
|
||||
return m_hSpace;
|
||||
} else {
|
||||
return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
|
||||
}
|
||||
}
|
||||
|
||||
int QFlowLayout::verticalSpacing() const
|
||||
{
|
||||
if (m_vSpace >= 0) {
|
||||
return m_vSpace;
|
||||
} else {
|
||||
return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
|
||||
}
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
int QFlowLayout::count() const
|
||||
{
|
||||
return itemList.size();
|
||||
}
|
||||
|
||||
QLayoutItem *QFlowLayout::itemAt(int index) const
|
||||
{
|
||||
return itemList.value(index);
|
||||
}
|
||||
|
||||
QLayoutItem *QFlowLayout::takeAt(int index)
|
||||
{
|
||||
if (index >= 0 && index < itemList.size())
|
||||
return itemList.takeAt(index);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
Qt::Orientations QFlowLayout::expandingDirections() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
bool QFlowLayout::hasHeightForWidth() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int QFlowLayout::heightForWidth(int width) const
|
||||
{
|
||||
int height = doLayout(QRect(0, 0, width, 0), true);
|
||||
return height;
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
void QFlowLayout::setGeometry(const QRect &rect)
|
||||
{
|
||||
QLayout::setGeometry(rect);
|
||||
doLayout(rect, false);
|
||||
}
|
||||
|
||||
QSize QFlowLayout::sizeHint() const
|
||||
{
|
||||
return minimumSize();
|
||||
}
|
||||
|
||||
QSize QFlowLayout::minimumSize() const
|
||||
{
|
||||
QSize size;
|
||||
QLayoutItem *item;
|
||||
foreach (item, itemList)
|
||||
size = size.expandedTo(item->minimumSize());
|
||||
|
||||
size += QSize(2*margin(), 2*margin());
|
||||
return size;
|
||||
}
|
||||
//! [8]
|
||||
|
||||
//! [9]
|
||||
int QFlowLayout::doLayout(const QRect &rect, bool testOnly) const
|
||||
{
|
||||
int left, top, right, bottom;
|
||||
getContentsMargins(&left, &top, &right, &bottom);
|
||||
QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
|
||||
int x = effectiveRect.x();
|
||||
int y = effectiveRect.y();
|
||||
int lineHeight = 0;
|
||||
//! [9]
|
||||
|
||||
//! [10]
|
||||
QLayoutItem *item;
|
||||
foreach (item, itemList) {
|
||||
QWidget *wid = item->widget();
|
||||
int spaceX = horizontalSpacing();
|
||||
if (spaceX == -1)
|
||||
spaceX = wid->style()->layoutSpacing(
|
||||
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
|
||||
int spaceY = verticalSpacing();
|
||||
if (spaceY == -1)
|
||||
spaceY = wid->style()->layoutSpacing(
|
||||
QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
|
||||
//! [10]
|
||||
//! [11]
|
||||
int nextX = x + item->sizeHint().width() + spaceX;
|
||||
if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
|
||||
x = effectiveRect.x();
|
||||
y = y + lineHeight + spaceY;
|
||||
nextX = x + item->sizeHint().width() + spaceX;
|
||||
lineHeight = 0;
|
||||
}
|
||||
|
||||
if (!testOnly)
|
||||
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
|
||||
|
||||
x = nextX;
|
||||
lineHeight = qMax(lineHeight, item->sizeHint().height());
|
||||
}
|
||||
return y + lineHeight - rect.y() + bottom;
|
||||
}
|
||||
//! [11]
|
||||
//! [12]
|
||||
int QFlowLayout::smartSpacing(QStyle::PixelMetric pm) const
|
||||
{
|
||||
QObject *parent = this->parent();
|
||||
if (!parent) {
|
||||
return -1;
|
||||
} else if (parent->isWidgetType()) {
|
||||
QWidget *pw = static_cast<QWidget *>(parent);
|
||||
return pw->style()->pixelMetric(pm, 0, pw);
|
||||
} else {
|
||||
return static_cast<QLayout *>(parent)->spacing();
|
||||
}
|
||||
}
|
||||
//! [12]
|
|
@ -0,0 +1,90 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QFlowLayout_H
|
||||
#define QFlowLayout_H
|
||||
|
||||
#include <QLayout>
|
||||
#include <QRect>
|
||||
#include <QStyle>
|
||||
//! [0]
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT QFlowLayout : public QLayout
|
||||
{
|
||||
public:
|
||||
explicit QFlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
|
||||
explicit QFlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
|
||||
~QFlowLayout();
|
||||
|
||||
void addItem(QLayoutItem *item) override;
|
||||
int horizontalSpacing() const;
|
||||
int verticalSpacing() const;
|
||||
Qt::Orientations expandingDirections() const override;
|
||||
bool hasHeightForWidth() const override;
|
||||
int heightForWidth(int) const override;
|
||||
int count() const override;
|
||||
QLayoutItem *itemAt(int index) const override;
|
||||
QSize minimumSize() const override;
|
||||
void setGeometry(const QRect &rect) override;
|
||||
QSize sizeHint() const override;
|
||||
QLayoutItem *takeAt(int index) override;
|
||||
|
||||
private:
|
||||
int doLayout(const QRect &rect, bool testOnly) const;
|
||||
int smartSpacing(QStyle::PixelMetric pm) const;
|
||||
|
||||
QList<QLayoutItem *> itemList;
|
||||
int m_hSpace;
|
||||
int m_vSpace;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // QFlowLayout_H
|
|
@ -0,0 +1,161 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CHistoryGraph: public QObject
|
||||
{
|
||||
public:
|
||||
CHistoryGraph(bool bSimpleMode = false, QColor BkG = Qt::white, QObject* parent = NULL) : QObject(parent) {
|
||||
m_SimpleMode = bSimpleMode;
|
||||
m_BkG = BkG;
|
||||
}
|
||||
~CHistoryGraph() {}
|
||||
|
||||
void AddValue(int Id, QColor Color)
|
||||
{
|
||||
m_Values.insert(Id, { 0.0, Color });
|
||||
}
|
||||
|
||||
void SetValue(int Id, float Value)
|
||||
{
|
||||
m_Values[Id].Value = Value;
|
||||
}
|
||||
|
||||
void Update(int CellHeight, int CellWidth)
|
||||
{
|
||||
Update(m_Graph, m_BkG, m_Values, CellHeight, CellWidth, m_SimpleMode);
|
||||
}
|
||||
|
||||
QImage GetImage() const { return m_Graph; }
|
||||
|
||||
struct SValue
|
||||
{
|
||||
float Value;
|
||||
QColor Color;
|
||||
};
|
||||
|
||||
static void Update(QImage& m_Graph, const QColor& m_BkG, const QMap<int, SValue>& m_Values, int CellHeight, int CellWidth, bool m_SimpleMode = true)
|
||||
{
|
||||
// init / resize
|
||||
if(m_Graph.height() != CellWidth /*|| m_Graph.width() != curHeight*/)
|
||||
{
|
||||
QImage Graph = QImage(CellHeight, CellWidth, QImage::Format_RGB32);
|
||||
QPainter qp(&Graph);
|
||||
qp.fillRect(-1, -1, CellHeight+1, CellWidth+1, m_BkG);
|
||||
if (!m_Graph.isNull())
|
||||
qp.drawImage(0, Graph.height() - m_Graph.height(), m_Graph);
|
||||
m_Graph = Graph;
|
||||
}
|
||||
|
||||
// shift
|
||||
uchar *dest = m_Graph.bits();
|
||||
int pos = m_Graph.sizeInBytes() - m_Graph.bytesPerLine();
|
||||
memmove(dest, dest + m_Graph.bytesPerLine(), pos);
|
||||
QPainter qp(&m_Graph);
|
||||
|
||||
// draw new data points
|
||||
int top = 0;
|
||||
|
||||
#if 0
|
||||
foreach(const SValue& Value, m_Values)
|
||||
{
|
||||
int x = (float)(m_Graph.width()) * Value.Value;
|
||||
if (x > top)
|
||||
top = x;
|
||||
|
||||
qp.setPen(Value.Color);
|
||||
qp.drawLine(0, m_Graph.height() - 1, x, m_Graph.height());
|
||||
}
|
||||
|
||||
qp.setPen(Qt::white);
|
||||
qp.drawLine(top, m_Graph.height() - 1, m_Graph.width()-1, m_Graph.height());
|
||||
#else
|
||||
dest += pos;
|
||||
memset(dest, 0, m_Graph.bytesPerLine()); // fill line black
|
||||
ASSERT(m_Graph.depth() == 32);
|
||||
int max = m_Graph.width();
|
||||
//ASSERT(max * 4 == m_Graph.bytesPerLine());
|
||||
|
||||
foreach(const SValue& Value, m_Values)
|
||||
{
|
||||
int x = (float)(max) * Value.Value;
|
||||
if (x > max)
|
||||
x = max;
|
||||
if (x > top)
|
||||
top = x;
|
||||
x *= 4;
|
||||
|
||||
int r, g, b;
|
||||
Value.Color.getRgb(&r, &g, &b);
|
||||
|
||||
|
||||
for (int i = 0; i < x; i += 4)
|
||||
{
|
||||
if (m_SimpleMode || *(quint32*)(dest + i) == 0)
|
||||
{
|
||||
dest[i ] = b;
|
||||
dest[i + 1] = g;
|
||||
dest[i + 2] = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
#define DIV 4/5
|
||||
int cb = (int)dest[i ]*DIV + b*DIV;
|
||||
int cg = (int)dest[i + 1]*DIV + g*DIV;
|
||||
int cr = (int)dest[i + 2]*DIV + r*DIV;
|
||||
|
||||
dest[i ] = qMin(cb, 255);
|
||||
dest[i + 1] = qMin(cg, 255);
|
||||
dest[i + 2] = qMin(cr, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fill whats left of the line
|
||||
/*top *= 4;
|
||||
if (top < m_Graph.bytesPerLine()) // fill rest white
|
||||
memset(dest + top, 0xFF, m_Graph.bytesPerLine() - top);*/
|
||||
{
|
||||
int r, g, b;
|
||||
m_BkG.getRgb(&r, &g, &b);
|
||||
|
||||
top *= 4;
|
||||
max *= 4;
|
||||
for (int i = top; i < max; i += 4)
|
||||
{
|
||||
dest[i] = b;
|
||||
dest[i + 1] = g;
|
||||
dest[i + 2] = r;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
QImage m_Graph;
|
||||
QColor m_BkG;
|
||||
QMap<int, SValue> m_Values;
|
||||
bool m_SimpleMode;
|
||||
};
|
||||
|
||||
class CHistoryWidget: public QWidget
|
||||
{
|
||||
public:
|
||||
CHistoryWidget(CHistoryGraph* pHistoryGraph, QWidget* parent = NULL) : QWidget(parent) { m_pHistoryGraph = pHistoryGraph; }
|
||||
~CHistoryWidget() {}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* e)
|
||||
{
|
||||
if (m_pHistoryGraph)
|
||||
{
|
||||
QImage HistoryGraph = m_pHistoryGraph->GetImage();
|
||||
QPainter qp(this);
|
||||
qp.translate(width() - HistoryGraph.height() - 1, height());
|
||||
qp.rotate(270);
|
||||
qp.drawImage(0, 0, HistoryGraph);
|
||||
}
|
||||
}
|
||||
|
||||
QPointer<CHistoryGraph> m_pHistoryGraph;
|
||||
};
|
|
@ -0,0 +1,307 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtWinExtras module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "IconExtreactor.h"
|
||||
|
||||
#include <QtWin>
|
||||
|
||||
//#include <iostream>
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <comdef.h>
|
||||
#include <commctrl.h>
|
||||
#include <objbase.h>
|
||||
#include <commoncontrols.h>
|
||||
|
||||
|
||||
/* This example demonstrates the Windows-specific image conversion
|
||||
* functions. */
|
||||
|
||||
/*struct PixmapEntry {
|
||||
QString name;
|
||||
QPixmap pixmap;
|
||||
};
|
||||
|
||||
typedef QVector<PixmapEntry> PixmapEntryList;*/
|
||||
|
||||
/*std::wostream &operator<<(std::wostream &str, const QString &s)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
str << reinterpret_cast<const wchar_t *>(s.utf16());
|
||||
#else
|
||||
str << s.toStdWString();
|
||||
#endif
|
||||
return str;
|
||||
}*/
|
||||
|
||||
QString formatSize(const QSize &size)
|
||||
{
|
||||
return QString::number(size.width()) + u'x' + QString::number(size.height());
|
||||
}
|
||||
|
||||
// Extract icons contained in executable or DLL using the Win32 API ExtractIconEx()
|
||||
PixmapEntryList extractIcons(const QString &sourceFile, bool large)
|
||||
{
|
||||
const QString nativeName = QDir::toNativeSeparators(sourceFile);
|
||||
const auto *sourceFileC = reinterpret_cast<const wchar_t *>(nativeName.utf16());
|
||||
const UINT iconCount = ExtractIconEx(sourceFileC, -1, nullptr, nullptr, 0);
|
||||
if (!iconCount) {
|
||||
//std::wcerr << sourceFile << " does not appear to contain icons.\n";
|
||||
return PixmapEntryList();
|
||||
}
|
||||
|
||||
QScopedArrayPointer<HICON> icons(new HICON[iconCount]);
|
||||
const UINT extractedIconCount = large ?
|
||||
ExtractIconEx(sourceFileC, 0, icons.data(), nullptr, iconCount) :
|
||||
ExtractIconEx(sourceFileC, 0, nullptr, icons.data(), iconCount);
|
||||
if (!extractedIconCount) {
|
||||
qErrnoWarning("Failed to extract icons from %s", qPrintable(sourceFile));
|
||||
return PixmapEntryList();
|
||||
}
|
||||
|
||||
PixmapEntryList result;
|
||||
result.reserve(int(extractedIconCount));
|
||||
|
||||
//std::wcout << sourceFile << " contains " << extractedIconCount << " icon(s).\n";
|
||||
|
||||
for (UINT i = 0; i < extractedIconCount; ++i) {
|
||||
PixmapEntry entry;
|
||||
entry.pixmap = QtWin::fromHICON(icons[i]);
|
||||
if (entry.pixmap.isNull()) {
|
||||
//std::wcerr << "Error converting icons.\n";
|
||||
return PixmapEntryList();
|
||||
}
|
||||
entry.name = QString::fromLatin1("%1_%2x%3").arg(i, 3, 10, QLatin1Char('0'))
|
||||
.arg(entry.pixmap.width()).arg(entry.pixmap.height());
|
||||
result.append(entry);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper for extracting large/jumbo icons available from Windows Vista onwards
|
||||
// via SHGetImageList().
|
||||
QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
|
||||
{
|
||||
QPixmap result;
|
||||
// For MinGW:
|
||||
const IID iID_IImageList = { 0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50} };
|
||||
|
||||
IImageList *imageList = nullptr;
|
||||
if (FAILED(SHGetImageList(iImageList, iID_IImageList, reinterpret_cast<void **>(&imageList))))
|
||||
return result;
|
||||
|
||||
HICON hIcon = nullptr;
|
||||
if (SUCCEEDED(imageList->GetIcon(info.iIcon, ILD_TRANSPARENT, &hIcon))) {
|
||||
result = QtWin::fromHICON(hIcon);
|
||||
DestroyIcon(hIcon);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Extract icons that would be displayed by the Explorer (shell)
|
||||
PixmapEntryList extractShellIcons(const QString &sourceFile, bool addOverlays)
|
||||
{
|
||||
enum { // Shell image list ids
|
||||
sHIL_EXTRALARGE = 0x2, // 48x48 or user-defined
|
||||
sHIL_JUMBO = 0x4 // 256x256 (Vista or later)
|
||||
};
|
||||
|
||||
struct FlagEntry {
|
||||
const char *name;
|
||||
unsigned flags;
|
||||
};
|
||||
|
||||
const FlagEntry modeEntries[] =
|
||||
{
|
||||
{"", 0},
|
||||
{"open", SHGFI_OPENICON},
|
||||
{"sel", SHGFI_SELECTED},
|
||||
};
|
||||
const FlagEntry standardSizeEntries[] =
|
||||
{
|
||||
{"s", SHGFI_SMALLICON},
|
||||
{"l", SHGFI_LARGEICON},
|
||||
{"sh", SHGFI_SHELLICONSIZE},
|
||||
};
|
||||
|
||||
const QString nativeName = QDir::toNativeSeparators(sourceFile);
|
||||
const auto *sourceFileC = reinterpret_cast<const wchar_t *>(nativeName.utf16());
|
||||
|
||||
SHFILEINFO info;
|
||||
unsigned int baseFlags = SHGFI_ICON | SHGFI_SYSICONINDEX | SHGFI_ICONLOCATION;
|
||||
if (addOverlays)
|
||||
baseFlags |= SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX;
|
||||
if (!QFileInfo(sourceFile).isDir())
|
||||
baseFlags |= SHGFI_USEFILEATTRIBUTES;
|
||||
|
||||
PixmapEntryList result;
|
||||
for (auto modeEntry : modeEntries) {
|
||||
const unsigned modeFlags = baseFlags | modeEntry.flags;
|
||||
QString modePrefix = QLatin1String("_shell_");
|
||||
if (modeEntry.name[0])
|
||||
modePrefix += QLatin1String(modeEntry.name) + u'_';
|
||||
for (auto standardSizeEntry : standardSizeEntries) {
|
||||
const unsigned flags = modeFlags | standardSizeEntry.flags;
|
||||
const QString prefix = modePrefix + QLatin1String(standardSizeEntry.name)
|
||||
+ u'_';
|
||||
ZeroMemory(&info, sizeof(SHFILEINFO));
|
||||
const HRESULT hr = SHGetFileInfo(sourceFileC, 0, &info, sizeof(SHFILEINFO), flags);
|
||||
if (FAILED(hr)) {
|
||||
_com_error error(hr);
|
||||
//std::wcerr << "SHGetFileInfo() failed for \"" << nativeName << "\", "
|
||||
// << std::hex << std::showbase << flags << std::dec << std::noshowbase
|
||||
// << " (" << prefix << "): " << error.ErrorMessage() << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (info.hIcon) {
|
||||
PixmapEntry entry;
|
||||
entry.pixmap = QtWin::fromHICON(info.hIcon);
|
||||
DestroyIcon(info.hIcon);
|
||||
if (entry.pixmap.isNull()) {
|
||||
//std::wcerr << "Error converting icons.\n";
|
||||
return PixmapEntryList();
|
||||
}
|
||||
entry.name = prefix + formatSize(entry.pixmap.size());
|
||||
|
||||
const int iconIndex = info.iIcon & 0xFFFFFF;
|
||||
const int overlayIconIndex = info.iIcon >> 24;
|
||||
|
||||
//std::wcout << "Obtained icon #" << iconIndex;
|
||||
//if (addOverlays)
|
||||
// std::wcout << " (overlay #" << overlayIconIndex << ')';
|
||||
//if (info.szDisplayName[0])
|
||||
// std::wcout << " from " << QString::fromWCharArray(info.szDisplayName);
|
||||
//std::wcout << " (" << entry.pixmap.width() << 'x'
|
||||
// << entry.pixmap.height() << ") for " << std::hex << std::showbase << flags
|
||||
// << std::dec << std::noshowbase << '\n';
|
||||
|
||||
result.append(entry);
|
||||
}
|
||||
} // for standardSizeEntryCount
|
||||
// Windows Vista onwards: extract large/jumbo icons
|
||||
if (info.hIcon) {
|
||||
const QPixmap extraLarge = pixmapFromShellImageList(sHIL_EXTRALARGE, info);
|
||||
if (!extraLarge.isNull()) {
|
||||
PixmapEntry entry;
|
||||
entry.pixmap = extraLarge;
|
||||
entry.name = modePrefix + QLatin1String("xl_") + formatSize(extraLarge.size());
|
||||
result.append(entry);
|
||||
}
|
||||
const QPixmap jumbo = pixmapFromShellImageList(sHIL_JUMBO, info);
|
||||
if (!jumbo.isNull()) {
|
||||
PixmapEntry entry;
|
||||
entry.pixmap = jumbo;
|
||||
entry.name = modePrefix + QLatin1String("jumbo_") + formatSize(extraLarge.size());
|
||||
result.append(entry);
|
||||
}
|
||||
}
|
||||
} // for modes
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
const char description[] =
|
||||
"\nExtracts Windows icons from executables, DLL or icon files and writes them\n"
|
||||
"out as numbered .png-files.\n"
|
||||
"When passing the --shell option, the icons displayed by Explorer are extracted.\n";
|
||||
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
QCoreApplication::setApplicationName(QStringLiteral("Icon Extractor"));
|
||||
QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
|
||||
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
|
||||
QCommandLineParser parser;
|
||||
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsCompactedShortOptions);
|
||||
parser.setApplicationDescription(QLatin1String(description));
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
const QCommandLineOption largeIconOption(QStringLiteral("large"), QStringLiteral("Extract large icons"));
|
||||
parser.addOption(largeIconOption);
|
||||
const QCommandLineOption shellIconOption(QStringLiteral("shell"), QStringLiteral("Extract shell icons using SHGetFileInfo()"));
|
||||
parser.addOption(shellIconOption);
|
||||
const QCommandLineOption shellOverlayOption(QStringLiteral("overlay"), QStringLiteral("Extract shell overlay icons"));
|
||||
parser.addOption(shellOverlayOption);
|
||||
parser.addPositionalArgument(QStringLiteral("file"), QStringLiteral("The file to open."));
|
||||
parser.addPositionalArgument(QStringLiteral("image_file_folder"), QStringLiteral("The folder to store the images."));
|
||||
parser.process(app);
|
||||
const QStringList &positionalArguments = parser.positionalArguments();
|
||||
if (positionalArguments.isEmpty())
|
||||
parser.showHelp(0);
|
||||
|
||||
QString imageFileRoot = positionalArguments.size() > 1 ? positionalArguments.at(1) : QDir::currentPath();
|
||||
const QFileInfo imageFileRootInfo(imageFileRoot);
|
||||
if (!imageFileRootInfo.isDir()) {
|
||||
std::wcerr << imageFileRoot << " is not a directory.\n";
|
||||
return 1;
|
||||
}
|
||||
const QString &sourceFile = positionalArguments.constFirst();
|
||||
imageFileRoot = imageFileRootInfo.absoluteFilePath() + u'/' + QFileInfo(sourceFile).baseName();
|
||||
|
||||
const PixmapEntryList pixmaps = parser.isSet(shellIconOption)
|
||||
? extractShellIcons(sourceFile, parser.isSet(shellOverlayOption))
|
||||
: extractIcons(sourceFile, parser.isSet(largeIconOption));
|
||||
|
||||
for (const auto &entry : pixmaps) {
|
||||
const QString fileName = imageFileRoot + entry.name + QLatin1String(".png");
|
||||
if (!entry.pixmap.save(fileName)) {
|
||||
std::wcerr << "Error writing image file " << fileName << ".\n";
|
||||
return 1;
|
||||
}
|
||||
std::wcout << "Wrote " << QDir::toNativeSeparators(fileName) << ".\n";
|
||||
}
|
||||
return 0;
|
||||
}*/
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
struct PixmapEntry {
|
||||
QString name;
|
||||
QPixmap pixmap;
|
||||
};
|
||||
|
||||
typedef QVector<PixmapEntry> PixmapEntryList;
|
||||
|
||||
MISCHELPERS_EXPORT PixmapEntryList extractIcons(const QString &sourceFile, bool large);
|
||||
MISCHELPERS_EXPORT PixmapEntryList extractShellIcons(const QString &sourceFile, bool addOverlays);
|
|
@ -0,0 +1,191 @@
|
|||
#include "stdafx.h"
|
||||
#include "ItemChooser.h"
|
||||
|
||||
CItemChooser::CItemChooser(const QString& Prompt, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
this->setWindowTitle(tr("Item Chooser"));
|
||||
|
||||
m_pMainLayout = new QVBoxLayout();
|
||||
this->setLayout(m_pMainLayout);
|
||||
|
||||
m_pLabel = new QLabel(Prompt.isNull() ? tr("Select items that will be used.") : Prompt, this);
|
||||
m_pLabel->setWordWrap(true);
|
||||
m_pMainLayout->addWidget(m_pLabel);
|
||||
|
||||
m_pCenterLayout = new QHBoxLayout();
|
||||
m_pMainLayout->addLayout(m_pCenterLayout);
|
||||
|
||||
m_pListAll = new QListWidget(this);
|
||||
m_pCenterLayout->addWidget(m_pListAll);
|
||||
m_pListAll->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
connect(m_pListAll, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(OnAdd()));
|
||||
|
||||
m_pMidleLayout = new QVBoxLayout();
|
||||
m_pCenterLayout->addLayout(m_pMidleLayout);
|
||||
|
||||
m_pMidleLayout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
|
||||
m_pBtnAdd = new QPushButton(tr("Add >"), this);
|
||||
connect(m_pBtnAdd, SIGNAL(pressed()), this, SLOT(OnAdd()));
|
||||
m_pMidleLayout->addWidget(m_pBtnAdd);
|
||||
|
||||
m_pBtnRemove = new QPushButton(tr("< Remove"), this);
|
||||
connect(m_pBtnRemove, SIGNAL(pressed()), this, SLOT(OnRemove()));
|
||||
m_pMidleLayout->addWidget(m_pBtnRemove);
|
||||
|
||||
m_pMidleLayout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
|
||||
m_pListChoosen = new QListWidget(this);
|
||||
m_pCenterLayout->addWidget(m_pListChoosen);
|
||||
m_pListChoosen->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
connect(m_pListChoosen, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(OnRemove()));
|
||||
|
||||
m_pRightLayout = new QVBoxLayout();
|
||||
m_pCenterLayout->addLayout(m_pRightLayout);
|
||||
|
||||
m_pBtnUp = new QPushButton(tr("Move Up"), this);
|
||||
connect(m_pBtnUp, SIGNAL(pressed()), this, SLOT(OnUp()));
|
||||
m_pRightLayout->addWidget(m_pBtnUp);
|
||||
|
||||
m_pBtnDown = new QPushButton(tr("Move Down"), this);
|
||||
connect(m_pBtnDown, SIGNAL(pressed()), this, SLOT(OnDown()));
|
||||
m_pRightLayout->addWidget(m_pBtnDown);
|
||||
|
||||
m_pRightLayout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
|
||||
m_InsertIndex = m_pMainLayout->count();
|
||||
|
||||
m_pButtonBox = new QDialogButtonBox(this);
|
||||
m_pMainLayout->addWidget(m_pButtonBox);
|
||||
m_pButtonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
connect(m_pButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
connect(m_pButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
}
|
||||
|
||||
void CItemChooser::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
void CItemChooser::SetPrompt(const QString& Text)
|
||||
{
|
||||
m_pLabel->setText(Text);
|
||||
}
|
||||
|
||||
void CItemChooser::AddWidgets(QList<QWidget*> Widgets)
|
||||
{
|
||||
foreach(QWidget* pWidget, Widgets)
|
||||
AddWidget(pWidget);
|
||||
}
|
||||
|
||||
void CItemChooser::AddWidget(QWidget* pWidget)
|
||||
{
|
||||
m_pMainLayout->insertWidget(m_InsertIndex++, pWidget);
|
||||
}
|
||||
|
||||
void CItemChooser::AddItem(const QString& Label, const QVariant& Data)
|
||||
{
|
||||
QListWidgetItem* pItem = new QListWidgetItem(Label);
|
||||
pItem->setData(Qt::UserRole, Data);
|
||||
m_pListAll->addItem(pItem);
|
||||
}
|
||||
|
||||
void CItemChooser::OnAdd()
|
||||
{
|
||||
foreach(QListWidgetItem* pItem, m_pListAll->selectedItems())
|
||||
AddItem(pItem);
|
||||
}
|
||||
|
||||
void CItemChooser::OnRemove()
|
||||
{
|
||||
foreach(QListWidgetItem* pItem, m_pListChoosen->selectedItems())
|
||||
RemoveItem(pItem);
|
||||
}
|
||||
|
||||
void CItemChooser::AddItem(QListWidgetItem* pItem)
|
||||
{
|
||||
pItem->setFlags(pItem->flags() & ~Qt::ItemIsSelectable & ~Qt::ItemIsEnabled);
|
||||
if (m_pListChoosen->findItems(pItem->text(), Qt::MatchExactly).count() > 0)
|
||||
return; // already added
|
||||
|
||||
QListWidgetItem* pChoosenItem = new QListWidgetItem(pItem->text());
|
||||
pChoosenItem->setData(Qt::UserRole, pItem->data(Qt::UserRole));
|
||||
m_pListChoosen->addItem(pChoosenItem);
|
||||
}
|
||||
|
||||
void CItemChooser::RemoveItem(QListWidgetItem* pChoosenItem)
|
||||
{
|
||||
foreach(QListWidgetItem* pItem, m_pListAll->findItems(pChoosenItem->text(), Qt::MatchExactly))
|
||||
pItem->setFlags(pItem->flags() | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
delete pChoosenItem;
|
||||
}
|
||||
|
||||
void CItemChooser::OnUp()
|
||||
{
|
||||
for (int i = 0; i < m_pListChoosen->count(); i++)
|
||||
{
|
||||
QListWidgetItem* pItem = m_pListChoosen->item(i);
|
||||
if (!pItem->isSelected())
|
||||
continue;
|
||||
if (!MoveItem(pItem, -1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CItemChooser::OnDown()
|
||||
{
|
||||
for (int i = m_pListChoosen->count()-1; i >= 0 ; i--)
|
||||
{
|
||||
QListWidgetItem* pItem = m_pListChoosen->item(i);
|
||||
if (!pItem->isSelected())
|
||||
continue;
|
||||
if (!MoveItem(pItem, 1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CItemChooser::MoveItem(QListWidgetItem* pItem, int Pos)
|
||||
{
|
||||
int currIndex = m_pListChoosen->row(pItem);
|
||||
|
||||
QListWidgetItem *pPrev = m_pListChoosen->item(m_pListChoosen->row(pItem) + Pos);
|
||||
if (!pPrev)
|
||||
return false;
|
||||
int prevIndex = m_pListChoosen->row(pPrev);
|
||||
|
||||
QListWidgetItem *pTemp = m_pListChoosen->takeItem(prevIndex);
|
||||
m_pListChoosen->insertItem(prevIndex, pItem);
|
||||
m_pListChoosen->insertItem(currIndex, pTemp);
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariantList CItemChooser::GetChoosenItems()
|
||||
{
|
||||
QVariantList ChoosenItems;
|
||||
for(int i=0; i < m_pListChoosen->count(); i++)
|
||||
ChoosenItems.append(m_pListChoosen->item(i)->data(Qt::UserRole));
|
||||
return ChoosenItems;
|
||||
}
|
||||
|
||||
void CItemChooser::ChooseItems(const QVariantList& ChoosenItems)
|
||||
{
|
||||
foreach(const QVariant& Data, ChoosenItems)
|
||||
ChooseItem(Data);
|
||||
}
|
||||
|
||||
void CItemChooser::ChooseItem(const QVariant& Data)
|
||||
{
|
||||
QListWidgetItem* pItem = NULL;
|
||||
for (int i = 0; i < m_pListAll->count(); i++)
|
||||
{
|
||||
if (m_pListAll->item(i)->data(Qt::UserRole) == Data)
|
||||
{
|
||||
pItem = m_pListAll->item(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pItem)
|
||||
AddItem(pItem);
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QListWidgetItem>
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CItemChooser : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CItemChooser(const QString& Prompt = QString(), QWidget *parent = Q_NULLPTR);
|
||||
|
||||
void SetPrompt(const QString& Text);
|
||||
void AddWidgets(QList<QWidget*> Widgets);
|
||||
void AddWidget(QWidget* pWidget);
|
||||
|
||||
void AddItem(const QString& Label, const QVariant& Data);
|
||||
void ChooseItems(const QVariantList& ChoosenItems);
|
||||
void ChooseItem(const QVariant& Data);
|
||||
|
||||
QVariantList GetChoosenItems();
|
||||
|
||||
private slots:
|
||||
void OnAdd();
|
||||
void OnRemove();
|
||||
void OnUp();
|
||||
void OnDown();
|
||||
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *e);
|
||||
|
||||
void AddItem(QListWidgetItem* pItem);
|
||||
void RemoveItem(QListWidgetItem* pChoosenItem);
|
||||
bool MoveItem(QListWidgetItem* pItem, int Pos);
|
||||
|
||||
private:
|
||||
|
||||
QVBoxLayout* m_pMainLayout;
|
||||
QLabel* m_pLabel;
|
||||
|
||||
QHBoxLayout* m_pCenterLayout;
|
||||
|
||||
QListWidget* m_pListAll;
|
||||
|
||||
QVBoxLayout* m_pMidleLayout;
|
||||
QPushButton* m_pBtnAdd;
|
||||
QPushButton* m_pBtnRemove;
|
||||
|
||||
QListWidget* m_pListChoosen;
|
||||
|
||||
QVBoxLayout* m_pRightLayout;
|
||||
QPushButton* m_pBtnUp;
|
||||
QPushButton* m_pBtnDown;
|
||||
|
||||
QDialogButtonBox* m_pButtonBox;
|
||||
|
||||
int m_InsertIndex;
|
||||
};
|
|
@ -0,0 +1,224 @@
|
|||
#include "stdafx.h"
|
||||
#include "KeyValueInputDialog.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
class CKeyValueInputDialogPrivate
|
||||
{
|
||||
public:
|
||||
CKeyValueInputDialogPrivate(QDialog *q)
|
||||
: clickedButton(0)
|
||||
{
|
||||
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
||||
|
||||
pixmapLabel = new QLabel(q);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
|
||||
pixmapLabel->setSizePolicy(sizePolicy);
|
||||
pixmapLabel->setVisible(false);
|
||||
|
||||
QSpacerItem *pixmapSpacer =
|
||||
new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
|
||||
|
||||
messageLabel = new QLabel(q);
|
||||
messageLabel->setMinimumSize(QSize(300, 0));
|
||||
messageLabel->setWordWrap(true);
|
||||
messageLabel->setOpenExternalLinks(true);
|
||||
messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
|
||||
|
||||
QSpacerItem *buttonSpacer =
|
||||
new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
|
||||
keyLabel = new QLabel(q);
|
||||
keyLabel->setText("Key:");
|
||||
|
||||
keyEdit = new QLineEdit(q);
|
||||
|
||||
valueLabel = new QLabel(q);
|
||||
valueLabel->setText("Value:");
|
||||
|
||||
valueEdit = new QTextEdit(q);
|
||||
|
||||
|
||||
buttonBox = new QDialogButtonBox(q);
|
||||
buttonBox->setOrientation(Qt::Horizontal);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
|
||||
QVBoxLayout *verticalLayout = new QVBoxLayout();
|
||||
verticalLayout->addWidget(pixmapLabel);
|
||||
verticalLayout->addItem(pixmapSpacer);
|
||||
|
||||
QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
|
||||
horizontalLayout_2->addLayout(verticalLayout);
|
||||
horizontalLayout_2->addWidget(messageLabel);
|
||||
|
||||
QFormLayout *horizontalLayout = new QFormLayout();
|
||||
horizontalLayout->addRow(keyLabel, keyEdit);
|
||||
horizontalLayout->addRow(valueLabel, valueEdit);
|
||||
|
||||
QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q);
|
||||
verticalLayout_2->addLayout(horizontalLayout_2);
|
||||
verticalLayout_2->addLayout(horizontalLayout);
|
||||
verticalLayout_2->addItem(buttonSpacer);
|
||||
verticalLayout_2->addWidget(buttonBox);
|
||||
}
|
||||
|
||||
QLabel *pixmapLabel;
|
||||
QLabel *messageLabel;
|
||||
QLabel *keyLabel;
|
||||
QLineEdit* keyEdit;
|
||||
QLabel *valueLabel;
|
||||
QTextEdit* valueEdit;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QAbstractButton *clickedButton;
|
||||
};
|
||||
|
||||
CKeyValueInputDialog::CKeyValueInputDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
d(new CKeyValueInputDialogPrivate(this))
|
||||
{
|
||||
setModal(true);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
|
||||
connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
||||
connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)),
|
||||
SLOT(slotClicked(QAbstractButton*)));
|
||||
}
|
||||
|
||||
CKeyValueInputDialog::~CKeyValueInputDialog()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::slotClicked(QAbstractButton *b)
|
||||
{
|
||||
d->clickedButton = b;
|
||||
}
|
||||
|
||||
QAbstractButton *CKeyValueInputDialog::clickedButton() const
|
||||
{
|
||||
return d->clickedButton;
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CKeyValueInputDialog::clickedStandardButton() const
|
||||
{
|
||||
if (d->clickedButton)
|
||||
return d->buttonBox->standardButton(d->clickedButton);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
QString CKeyValueInputDialog::text() const
|
||||
{
|
||||
return d->messageLabel->text();
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::setText(const QString &t)
|
||||
{
|
||||
d->messageLabel->setText(t);
|
||||
}
|
||||
|
||||
QString CKeyValueInputDialog::keyLabel() const
|
||||
{
|
||||
return d->keyLabel->text();
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::setKeyLabel(const QString &t)
|
||||
{
|
||||
return d->keyLabel->setText(t);
|
||||
}
|
||||
|
||||
QString CKeyValueInputDialog::key() const
|
||||
{
|
||||
return d->keyEdit->text();
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::setKey(const QString &t)
|
||||
{
|
||||
return d->keyEdit->setText(t);
|
||||
}
|
||||
|
||||
bool CKeyValueInputDialog::keyReadOnly() const
|
||||
{
|
||||
return d->keyEdit->isReadOnly();
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::setKeyReadOnly(bool r)
|
||||
{
|
||||
return d->keyEdit->setReadOnly(r);
|
||||
}
|
||||
|
||||
QString CKeyValueInputDialog::valueLabel() const
|
||||
{
|
||||
return d->valueLabel->text();
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::setValueLabel(const QString &t)
|
||||
{
|
||||
return d->valueLabel->setText(t);
|
||||
}
|
||||
|
||||
QString CKeyValueInputDialog::value() const
|
||||
{
|
||||
return d->valueEdit->toPlainText();
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::setValue(const QString &t)
|
||||
{
|
||||
return d->valueEdit->setText(t);
|
||||
}
|
||||
|
||||
QPixmap CKeyValueInputDialog::iconPixmap() const
|
||||
{
|
||||
if (const QPixmap *p = d->pixmapLabel->pixmap())
|
||||
return QPixmap(*p);
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::setIconPixmap(const QPixmap &p)
|
||||
{
|
||||
d->pixmapLabel->setPixmap(p);
|
||||
d->pixmapLabel->setVisible(!p.isNull());
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButtons CKeyValueInputDialog::standardButtons() const
|
||||
{
|
||||
return d->buttonBox->standardButtons();
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::setStandardButtons(QDialogButtonBox::StandardButtons s)
|
||||
{
|
||||
d->buttonBox->setStandardButtons(s);
|
||||
}
|
||||
|
||||
QPushButton *CKeyValueInputDialog::button(QDialogButtonBox::StandardButton b) const
|
||||
{
|
||||
return d->buttonBox->button(b);
|
||||
}
|
||||
|
||||
QPushButton *CKeyValueInputDialog::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
|
||||
{
|
||||
return d->buttonBox->addButton(text, role);
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CKeyValueInputDialog::defaultButton() const
|
||||
{
|
||||
foreach (QAbstractButton *b, d->buttonBox->buttons())
|
||||
if (QPushButton *pb = qobject_cast<QPushButton *>(b))
|
||||
if (pb->isDefault())
|
||||
return d->buttonBox->standardButton(pb);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
void CKeyValueInputDialog::setDefaultButton(QDialogButtonBox::StandardButton s)
|
||||
{
|
||||
if (QPushButton *b = d->buttonBox->button(s)) {
|
||||
b->setDefault(true);
|
||||
b->setFocus();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef KEYVALUEINPUTDIALOG_H
|
||||
#define KEYVALUEINPUTDIALOG_H
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QMessageBox>
|
||||
|
||||
class CKeyValueInputDialogPrivate;
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CKeyValueInputDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton)
|
||||
|
||||
public:
|
||||
explicit CKeyValueInputDialog(QWidget *parent = NULL);
|
||||
virtual ~CKeyValueInputDialog();
|
||||
|
||||
QString text() const;
|
||||
void setText(const QString &);
|
||||
|
||||
QString keyLabel() const;
|
||||
void setKeyLabel(const QString &);
|
||||
|
||||
QString key() const;
|
||||
void setKey(const QString &);
|
||||
|
||||
bool keyReadOnly() const;
|
||||
void setKeyReadOnly(bool);
|
||||
|
||||
QString valueLabel() const;
|
||||
void setValueLabel(const QString &);
|
||||
|
||||
QString value() const;
|
||||
void setValue(const QString &);
|
||||
|
||||
|
||||
QDialogButtonBox::StandardButtons standardButtons() const;
|
||||
void setStandardButtons(QDialogButtonBox::StandardButtons s);
|
||||
QPushButton *button(QDialogButtonBox::StandardButton b) const;
|
||||
QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role);
|
||||
|
||||
QDialogButtonBox::StandardButton defaultButton() const;
|
||||
void setDefaultButton(QDialogButtonBox::StandardButton s);
|
||||
|
||||
// See static QMessageBox::standardPixmap()
|
||||
QPixmap iconPixmap() const;
|
||||
void setIconPixmap (const QPixmap &p);
|
||||
|
||||
// Query the result
|
||||
QAbstractButton *clickedButton() const;
|
||||
QDialogButtonBox::StandardButton clickedStandardButton() const;
|
||||
|
||||
private slots:
|
||||
void slotClicked(QAbstractButton *b);
|
||||
|
||||
private:
|
||||
CKeyValueInputDialogPrivate *d;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // HCOMBODIALOG_H
|
|
@ -0,0 +1,305 @@
|
|||
#include "stdafx.h"
|
||||
#include "ListItemModel.h"
|
||||
|
||||
#define FIRST_COLUMN 0
|
||||
|
||||
bool CListItemModel::m_DarkMode = false;
|
||||
|
||||
CListItemModel::CListItemModel(QObject *parent)
|
||||
: QAbstractItemModelEx(parent)
|
||||
{
|
||||
m_bUseIcons = false;
|
||||
}
|
||||
|
||||
CListItemModel::~CListItemModel()
|
||||
{
|
||||
foreach(SListNode* pNode, m_List)
|
||||
delete pNode;
|
||||
}
|
||||
|
||||
int CListItemModel::GetRow(SListNode* pNode) const
|
||||
{
|
||||
int Index = m_RevList.value(pNode, -1);
|
||||
ASSERT(Index != -1);
|
||||
ASSERT(m_List[Index] == pNode);
|
||||
return Index;
|
||||
}
|
||||
|
||||
void CSimpleListModel::Sync(QList<QVariantMap> List)
|
||||
{
|
||||
QList<SListNode*> New;
|
||||
QHash<QVariant, SListNode*> Old = m_Map;
|
||||
|
||||
foreach (const QVariantMap& Cur, List)
|
||||
{
|
||||
QVariant ID = Cur["ID"];
|
||||
|
||||
int Row = -1;
|
||||
SListNode* pNode = static_cast<SListNode*>(Old[ID]);
|
||||
if(!pNode)
|
||||
{
|
||||
pNode = static_cast<SListNode*>(MkNode(ID));
|
||||
pNode->Values.resize(columnCount());
|
||||
pNode->IsBold = Cur["IsBold"].toBool();
|
||||
pNode->Icon = Cur["Icon"];
|
||||
New.append(pNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Old[ID] = NULL;
|
||||
Row = GetRow(pNode);
|
||||
}
|
||||
|
||||
int Col = 0;
|
||||
bool State = false;
|
||||
bool Changed = false;
|
||||
|
||||
QVariantMap Values = Cur["Values"].toMap();
|
||||
for(int section = FIRST_COLUMN; section < columnCount(); section++)
|
||||
{
|
||||
if (!m_Columns.contains(section))
|
||||
continue; // ignore columns which are hidden
|
||||
|
||||
QVariant Value = Values[QString::number(section)];
|
||||
|
||||
SListNode::SValue& ColValue = pNode->Values[section];
|
||||
|
||||
if (ColValue.Raw != Value)
|
||||
{
|
||||
Changed = true;
|
||||
ColValue.Raw = Value;
|
||||
|
||||
//ColValue.Formated =
|
||||
}
|
||||
|
||||
if(State != Changed)
|
||||
{
|
||||
if(State && Row != -1)
|
||||
emit dataChanged(createIndex(Row, Col), createIndex(Row, section-1));
|
||||
State = Changed;
|
||||
Col = section;
|
||||
}
|
||||
Changed = false;
|
||||
}
|
||||
if(State && Row != -1)
|
||||
emit dataChanged(createIndex(Row, Col, pNode), createIndex(Row, columnCount()-1, pNode));
|
||||
}
|
||||
|
||||
CListItemModel::Sync(New, Old);
|
||||
}
|
||||
|
||||
void CListItemModel::Sync(QList<SListNode*>& New, QHash<QVariant, SListNode*>& Old)
|
||||
{
|
||||
int Removed = 0;
|
||||
|
||||
int Begin = -1;
|
||||
int End = -1;
|
||||
for(int i = m_List.count()-1; i >= -1; i--)
|
||||
{
|
||||
QVariant ID = i >= 0 ? m_List[i]->ID : QVariant();
|
||||
if(!ID.isNull() && (Old.value(ID) != NULL)) // remove it
|
||||
{
|
||||
m_Map.remove(ID);
|
||||
if(End == -1)
|
||||
End = i;
|
||||
}
|
||||
else if(End != -1) // keep it and remove whatis to be removed at once
|
||||
{
|
||||
Begin = i + 1;
|
||||
|
||||
beginRemoveRows(QModelIndex(), Begin, End);
|
||||
for (int j = End; j >= Begin; j--)
|
||||
{
|
||||
Removed++;
|
||||
|
||||
SListNode* pNode = m_List.takeAt(j);
|
||||
m_RevList.remove(pNode);
|
||||
delete pNode;
|
||||
}
|
||||
endRemoveRows();
|
||||
|
||||
End = -1;
|
||||
Begin = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// if something was removed we need to update the row cache
|
||||
if (Removed > 0)
|
||||
{
|
||||
ASSERT(m_RevList.size() == m_List.size());
|
||||
for (int i = 0; i < m_List.count(); i++)
|
||||
m_RevList[m_List[i]] = i;
|
||||
}
|
||||
|
||||
Begin = m_List.count();
|
||||
for(QList<SListNode*>::iterator I = New.begin(); I != New.end(); I++)
|
||||
{
|
||||
SListNode* pNode = *I;
|
||||
m_Map.insert(pNode->ID, pNode);
|
||||
|
||||
int Index = m_List.size();
|
||||
m_List.append(pNode);
|
||||
m_RevList.insert(pNode, Index);
|
||||
}
|
||||
End = m_List.count();
|
||||
if(Begin < End)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), Begin, End-1);
|
||||
endInsertRows();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex CListItemModel::FindIndex(const QVariant& ID)
|
||||
{
|
||||
if(SListNode* pNode = m_Map.value(ID))
|
||||
{
|
||||
int row = m_List.indexOf(pNode);
|
||||
ASSERT(row != -1);
|
||||
return createIndex(row, FIRST_COLUMN, pNode);
|
||||
}
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
void CListItemModel::Clear()
|
||||
{
|
||||
//beginResetModel();
|
||||
if (rowCount() == 0)
|
||||
return;
|
||||
beginRemoveRows(QModelIndex(), 0, rowCount()-1);
|
||||
foreach(SListNode* pNode, m_List)
|
||||
delete pNode;
|
||||
m_List.clear();
|
||||
m_RevList.clear();
|
||||
m_Map.clear();
|
||||
endRemoveRows();
|
||||
//endResetModel();
|
||||
}
|
||||
|
||||
QVariant CListItemModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
return Data(index, role, index.column());
|
||||
}
|
||||
|
||||
QVariant CListItemModel::Data(const QModelIndex &index, int role, int section) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
//if(role == Qt::SizeHintRole )
|
||||
// return QSize(64,16); // for fixing height
|
||||
|
||||
SListNode* pNode = static_cast<SListNode*>(index.internalPointer());
|
||||
|
||||
switch(role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
SListNode::SValue& Value = pNode->Values[section];
|
||||
return Value.Formated.isValid() ? Value.Formated : Value.Raw;
|
||||
}
|
||||
case Qt::EditRole: // sort role
|
||||
{
|
||||
return pNode->Values[section].Raw;
|
||||
}
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
QString ToolTip;
|
||||
emit ToolTipCallback(pNode->ID, ToolTip);
|
||||
if(!ToolTip.isNull())
|
||||
return ToolTip;
|
||||
break;
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
{
|
||||
if (m_bUseIcons && section == FIRST_COLUMN)
|
||||
return pNode->Icon.isValid() ? pNode->Icon : GetDefaultIcon();
|
||||
break;
|
||||
}
|
||||
case Qt::FontRole:
|
||||
{
|
||||
if (section == FIRST_COLUMN && pNode->IsBold)
|
||||
{
|
||||
QFont fnt;
|
||||
fnt.setBold(true);
|
||||
return fnt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::BackgroundRole:
|
||||
{
|
||||
if(!m_DarkMode)
|
||||
return pNode->Color.isValid() ? pNode->Color : QVariant();
|
||||
break;
|
||||
}
|
||||
case Qt::ForegroundRole:
|
||||
{
|
||||
if(m_DarkMode)
|
||||
return pNode->Color.isValid() ? pNode->Color : QVariant();
|
||||
else if (pNode->IsGray)
|
||||
{
|
||||
QColor Color = Qt::darkGray;
|
||||
return QBrush(Color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::UserRole:
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case FIRST_COLUMN: return pNode->ID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags CListItemModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
QModelIndex CListItemModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
|
||||
if (parent.isValid())
|
||||
return QModelIndex();
|
||||
if(m_List.count() > row)
|
||||
return createIndex(row, column, m_List[row]);
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex CListItemModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int CListItemModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.column() > 0)
|
||||
return 0;
|
||||
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
return m_List.count();
|
||||
}
|
||||
|
||||
int CSimpleListModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return m_Headers.count();
|
||||
}
|
||||
|
||||
QVariant CSimpleListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
{
|
||||
if (section < m_Headers.size())
|
||||
return m_Headers.at(section);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
#pragma once
|
||||
#include "TreeViewEx.h"
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CListItemModel : public QAbstractItemModelEx
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CListItemModel(QObject *parent = 0);
|
||||
virtual ~CListItemModel();
|
||||
|
||||
void SetUseIcons(bool bUseIcons) { m_bUseIcons = bUseIcons; }
|
||||
static void SetDarkMode(bool bDark) { m_DarkMode = bDark;}
|
||||
|
||||
QModelIndex FindIndex(const QVariant& ID);
|
||||
|
||||
QVariant Data(const QModelIndex &index, int role, int section) const;
|
||||
|
||||
// derived functions
|
||||
virtual QVariant data(const QModelIndex &index, int role) const;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QModelIndex parent(const QModelIndex &index) const;
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const = 0;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const = 0;
|
||||
|
||||
public slots:
|
||||
void Clear();
|
||||
|
||||
signals:
|
||||
void ToolTipCallback(const QVariant& ID, QString& ToolTip) const;
|
||||
|
||||
protected:
|
||||
struct SListNode
|
||||
{
|
||||
SListNode(const QVariant& Id)
|
||||
{
|
||||
ID = Id;
|
||||
|
||||
IsBold = false;
|
||||
IsGray = false;
|
||||
}
|
||||
virtual ~SListNode()
|
||||
{
|
||||
}
|
||||
|
||||
QVariant ID;
|
||||
|
||||
QVariant Icon;
|
||||
bool IsBold;
|
||||
bool IsGray;
|
||||
QColor Color;
|
||||
struct SValue
|
||||
{
|
||||
QVariant Raw;
|
||||
QVariant Formated;
|
||||
};
|
||||
QVector<SValue> Values;
|
||||
};
|
||||
|
||||
virtual SListNode* MkNode(const QVariant& Id) = 0; // { return new SListNode(Id); }
|
||||
|
||||
void Sync(QList<SListNode*>& New, QHash<QVariant, SListNode*>& Old);
|
||||
|
||||
virtual QVariant GetDefaultIcon() const { return QVariant(); }
|
||||
|
||||
int GetRow(SListNode* pNode) const;
|
||||
|
||||
QList<SListNode*> m_List;
|
||||
QHash<void*, int> m_RevList;
|
||||
QHash<QVariant, SListNode*> m_Map;
|
||||
bool m_bUseIcons;
|
||||
|
||||
static bool m_DarkMode;
|
||||
};
|
||||
|
||||
class MISCHELPERS_EXPORT CSimpleListModel : public CListItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CSimpleListModel(QObject *parent = 0) : CListItemModel(parent) {}
|
||||
|
||||
void Sync(QList<QVariantMap> List);
|
||||
|
||||
void setHeaderLabels(const QStringList& Columns) { m_Headers = Columns; }
|
||||
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
||||
protected:
|
||||
virtual SListNode* MkNode(const QVariant& Id) { return new SListNode(Id); }
|
||||
|
||||
QStringList m_Headers;
|
||||
};
|
|
@ -0,0 +1,169 @@
|
|||
#include "stdafx.h"
|
||||
#include "MultiLineInputDialog.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
class CMultiLineInputDialogPrivate
|
||||
{
|
||||
public:
|
||||
CMultiLineInputDialogPrivate(QDialog *q)
|
||||
: clickedButton(0)
|
||||
{
|
||||
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
||||
|
||||
pixmapLabel = new QLabel(q);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
|
||||
pixmapLabel->setSizePolicy(sizePolicy);
|
||||
pixmapLabel->setVisible(false);
|
||||
|
||||
QSpacerItem *pixmapSpacer =
|
||||
new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
|
||||
|
||||
messageLabel = new QLabel(q);
|
||||
messageLabel->setMinimumSize(QSize(300, 0));
|
||||
messageLabel->setWordWrap(true);
|
||||
messageLabel->setOpenExternalLinks(true);
|
||||
messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
|
||||
|
||||
QSpacerItem *buttonSpacer =
|
||||
new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
|
||||
edit = new QPlainTextEdit(q);
|
||||
|
||||
|
||||
buttonBox = new QDialogButtonBox(q);
|
||||
buttonBox->setOrientation(Qt::Horizontal);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
|
||||
QVBoxLayout *verticalLayout = new QVBoxLayout();
|
||||
verticalLayout->addWidget(pixmapLabel);
|
||||
verticalLayout->addItem(pixmapSpacer);
|
||||
|
||||
QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
|
||||
horizontalLayout_2->addLayout(verticalLayout);
|
||||
horizontalLayout_2->addWidget(messageLabel);
|
||||
|
||||
QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q);
|
||||
verticalLayout_2->addLayout(horizontalLayout_2);
|
||||
verticalLayout_2->addWidget(edit);
|
||||
verticalLayout_2->addItem(buttonSpacer);
|
||||
verticalLayout_2->addWidget(buttonBox);
|
||||
}
|
||||
|
||||
QLabel *pixmapLabel;
|
||||
QLabel *messageLabel;
|
||||
QPlainTextEdit* edit;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QAbstractButton *clickedButton;
|
||||
};
|
||||
|
||||
CMultiLineInputDialog::CMultiLineInputDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
d(new CMultiLineInputDialogPrivate(this))
|
||||
{
|
||||
setModal(true);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
|
||||
connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
||||
connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)),
|
||||
SLOT(slotClicked(QAbstractButton*)));
|
||||
}
|
||||
|
||||
CMultiLineInputDialog::~CMultiLineInputDialog()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void CMultiLineInputDialog::slotClicked(QAbstractButton *b)
|
||||
{
|
||||
d->clickedButton = b;
|
||||
}
|
||||
|
||||
QAbstractButton *CMultiLineInputDialog::clickedButton() const
|
||||
{
|
||||
return d->clickedButton;
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CMultiLineInputDialog::clickedStandardButton() const
|
||||
{
|
||||
if (d->clickedButton)
|
||||
return d->buttonBox->standardButton(d->clickedButton);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
QString CMultiLineInputDialog::text() const
|
||||
{
|
||||
return d->messageLabel->text();
|
||||
}
|
||||
|
||||
void CMultiLineInputDialog::setText(const QString &t)
|
||||
{
|
||||
d->messageLabel->setText(t);
|
||||
}
|
||||
|
||||
QString CMultiLineInputDialog::value() const
|
||||
{
|
||||
return d->edit->toPlainText();
|
||||
}
|
||||
|
||||
void CMultiLineInputDialog::setValue(const QString &t)
|
||||
{
|
||||
d->edit->setPlainText(t);
|
||||
}
|
||||
|
||||
QPixmap CMultiLineInputDialog::iconPixmap() const
|
||||
{
|
||||
if (const QPixmap *p = d->pixmapLabel->pixmap())
|
||||
return QPixmap(*p);
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
void CMultiLineInputDialog::setIconPixmap(const QPixmap &p)
|
||||
{
|
||||
d->pixmapLabel->setPixmap(p);
|
||||
d->pixmapLabel->setVisible(!p.isNull());
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButtons CMultiLineInputDialog::standardButtons() const
|
||||
{
|
||||
return d->buttonBox->standardButtons();
|
||||
}
|
||||
|
||||
void CMultiLineInputDialog::setStandardButtons(QDialogButtonBox::StandardButtons s)
|
||||
{
|
||||
d->buttonBox->setStandardButtons(s);
|
||||
}
|
||||
|
||||
QPushButton *CMultiLineInputDialog::button(QDialogButtonBox::StandardButton b) const
|
||||
{
|
||||
return d->buttonBox->button(b);
|
||||
}
|
||||
|
||||
QPushButton *CMultiLineInputDialog::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
|
||||
{
|
||||
return d->buttonBox->addButton(text, role);
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton CMultiLineInputDialog::defaultButton() const
|
||||
{
|
||||
foreach (QAbstractButton *b, d->buttonBox->buttons())
|
||||
if (QPushButton *pb = qobject_cast<QPushButton *>(b))
|
||||
if (pb->isDefault())
|
||||
return d->buttonBox->standardButton(pb);
|
||||
return QDialogButtonBox::NoButton;
|
||||
}
|
||||
|
||||
void CMultiLineInputDialog::setDefaultButton(QDialogButtonBox::StandardButton s)
|
||||
{
|
||||
if (QPushButton *b = d->buttonBox->button(s)) {
|
||||
b->setDefault(true);
|
||||
b->setFocus();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef MULTILINEINPUTDIALOG_H
|
||||
#define MULTILINEINPUTDIALOG_H
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QMessageBox>
|
||||
|
||||
class CMultiLineInputDialogPrivate;
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CMultiLineInputDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons)
|
||||
Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton)
|
||||
|
||||
public:
|
||||
explicit CMultiLineInputDialog(QWidget *parent = NULL);
|
||||
virtual ~CMultiLineInputDialog();
|
||||
|
||||
QString text() const;
|
||||
void setText(const QString &);
|
||||
|
||||
QString value() const;
|
||||
void setValue(const QString &);
|
||||
|
||||
|
||||
QDialogButtonBox::StandardButtons standardButtons() const;
|
||||
void setStandardButtons(QDialogButtonBox::StandardButtons s);
|
||||
QPushButton *button(QDialogButtonBox::StandardButton b) const;
|
||||
QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role);
|
||||
|
||||
QDialogButtonBox::StandardButton defaultButton() const;
|
||||
void setDefaultButton(QDialogButtonBox::StandardButton s);
|
||||
|
||||
// See static QMessageBox::standardPixmap()
|
||||
QPixmap iconPixmap() const;
|
||||
void setIconPixmap (const QPixmap &p);
|
||||
|
||||
// Query the result
|
||||
QAbstractButton *clickedButton() const;
|
||||
QDialogButtonBox::StandardButton clickedStandardButton() const;
|
||||
|
||||
private slots:
|
||||
void slotClicked(QAbstractButton *b);
|
||||
|
||||
private:
|
||||
CMultiLineInputDialogPrivate *d;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // HMULTILINEINPUTDIALOG_H
|
|
@ -0,0 +1,220 @@
|
|||
#include "stdafx.h"
|
||||
#include "PanelView.h"
|
||||
|
||||
bool CPanelView::m_SimpleFormat = false;
|
||||
int CPanelView::m_MaxCellWidth = 0;
|
||||
QString CPanelView::m_CellSeparator = "\t";
|
||||
|
||||
CPanelView::CPanelView(QWidget *parent)
|
||||
:QWidget(parent)
|
||||
{
|
||||
//m_CopyAll = false;
|
||||
|
||||
m_pMenu = new QMenu();
|
||||
}
|
||||
|
||||
CPanelView::~CPanelView()
|
||||
{
|
||||
}
|
||||
|
||||
void CPanelView::AddPanelItemsToMenu(bool bAddSeparator)
|
||||
{
|
||||
if(bAddSeparator)
|
||||
m_pMenu->addSeparator();
|
||||
m_pCopyCell = m_pMenu->addAction(tr("Copy Cell"), this, SLOT(OnCopyCell()));
|
||||
m_pCopyRow = m_pMenu->addAction(tr("Copy Row"), this, SLOT(OnCopyRow()));
|
||||
m_pCopyRow->setShortcut(QKeySequence::Copy);
|
||||
m_pCopyRow->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
this->addAction(m_pCopyRow);
|
||||
m_pCopyPanel = m_pMenu->addAction(tr("Copy Panel"), this, SLOT(OnCopyPanel()));
|
||||
}
|
||||
|
||||
void CPanelView::OnMenu(const QPoint& Point)
|
||||
{
|
||||
QModelIndex Index = GetView()->currentIndex();
|
||||
|
||||
m_pCopyCell->setEnabled(Index.isValid());
|
||||
m_pCopyRow->setEnabled(Index.isValid());
|
||||
|
||||
m_pMenu->popup(QCursor::pos());
|
||||
}
|
||||
|
||||
void CPanelView::OnCopyCell()
|
||||
{
|
||||
QAbstractItemModel* pModel = GetModel();
|
||||
QTreeView * pView = GetView();
|
||||
|
||||
QModelIndex Index = pView->currentIndex();
|
||||
QModelIndex ModelIndex = MapToSource(Index);
|
||||
int Column = ModelIndex.column();
|
||||
|
||||
QList<QStringList> Rows;
|
||||
foreach(const QModelIndex& Index, pView->selectionModel()->selectedIndexes())
|
||||
{
|
||||
if (Index.column() != Column)
|
||||
continue;
|
||||
QModelIndex CurIndex = pModel->index(Index.row(), Column, Index.parent());
|
||||
QString Cell = pModel->data(CurIndex, Qt::DisplayRole).toString();
|
||||
Rows.append(QStringList() << Cell);
|
||||
}
|
||||
FormatAndCopy(Rows, false);
|
||||
}
|
||||
|
||||
void CPanelView::OnCopyRow()
|
||||
{
|
||||
QAbstractItemModel* pModel = GetModel();
|
||||
QTreeView * pView = GetView();
|
||||
|
||||
int Column = 0; // find first not hidden column
|
||||
for (int i = 0; i < pModel->columnCount(); i++)
|
||||
{
|
||||
if (!pView->isColumnHidden(i) || m_ForcedColumns.contains(i))
|
||||
{
|
||||
Column = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QList<QStringList> Rows;
|
||||
foreach(const QModelIndex& Index, pView->selectionModel()->selectedIndexes())
|
||||
{
|
||||
if (Index.column() != Column)
|
||||
continue;
|
||||
|
||||
QModelIndex ModelIndex = MapToSource(Index);
|
||||
Rows.append(CopyRow(ModelIndex));
|
||||
}
|
||||
FormatAndCopy(Rows);
|
||||
}
|
||||
|
||||
QStringList CPanelView::CopyHeader()
|
||||
{
|
||||
QAbstractItemModel* pModel = GetModel();
|
||||
QTreeView * pView = GetView();
|
||||
|
||||
QStringList Headder;
|
||||
for (int i = 0; i < pModel->columnCount(); i++)
|
||||
{
|
||||
if (/*!m_CopyAll &&*/ pView->isColumnHidden(i) && !m_ForcedColumns.contains(i))
|
||||
continue;
|
||||
QString Cell = pModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
|
||||
if (!m_SimpleFormat)
|
||||
Cell = "|" + Cell + "|";
|
||||
Headder.append(Cell);
|
||||
}
|
||||
return Headder;
|
||||
}
|
||||
|
||||
QStringList CPanelView::CopyRow(const QModelIndex& ModelIndex, int Level)
|
||||
{
|
||||
QAbstractItemModel* pModel = GetModel();
|
||||
QTreeView * pView = GetView();
|
||||
|
||||
QStringList Cells;
|
||||
for (int i = 0; i < pModel->columnCount(); i++)
|
||||
{
|
||||
if (/*!m_CopyAll &&*/ pView->isColumnHidden(i) && !m_ForcedColumns.contains(i))
|
||||
continue;
|
||||
QModelIndex CellIndex = pModel->index(ModelIndex.row(), i, ModelIndex.parent());
|
||||
QString Cell = pModel->data(CellIndex, Qt::DisplayRole).toString();
|
||||
if (Level && i == 0)
|
||||
Cell.prepend(QString(Level, '_') + " ");
|
||||
Cells.append(Cell);
|
||||
}
|
||||
return Cells;
|
||||
}
|
||||
|
||||
void CPanelView::RecursiveCopyPanel(const QModelIndex& ModelIndex, QList<QStringList>& Rows, int Level)
|
||||
{
|
||||
QAbstractItemModel* pModel = GetModel();
|
||||
|
||||
Rows.append(CopyRow(ModelIndex, Level));
|
||||
|
||||
for (int i = 0; i < pModel->rowCount(ModelIndex); i++)
|
||||
{
|
||||
QModelIndex SubIndex = pModel->index(i, 0, ModelIndex);
|
||||
RecursiveCopyPanel(SubIndex, Rows, Level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void CPanelView::OnCopyPanel()
|
||||
{
|
||||
QAbstractItemModel* pModel = GetModel();
|
||||
|
||||
QList<QStringList> Rows;
|
||||
for (int i = 0; i < pModel->rowCount(); ++i)
|
||||
{
|
||||
QModelIndex ModelIndex = pModel->index(i, 0);
|
||||
RecursiveCopyPanel(ModelIndex, Rows);
|
||||
}
|
||||
FormatAndCopy(Rows);
|
||||
}
|
||||
|
||||
void CPanelView::FormatAndCopy(QList<QStringList> Rows, bool Headder)
|
||||
{
|
||||
int RowCount = Rows.length();
|
||||
|
||||
if (Headder)
|
||||
{
|
||||
Rows.prepend(QStringList());
|
||||
Rows.prepend(CopyHeader());
|
||||
Rows.prepend(QStringList());
|
||||
}
|
||||
|
||||
QStringList TextRows;
|
||||
if (m_SimpleFormat || !Headder)
|
||||
{
|
||||
foreach(const QStringList& Row, Rows)
|
||||
TextRows.append(Row.join(m_CellSeparator));
|
||||
}
|
||||
else if(Rows.size() > (Headder ? 3 : 0))
|
||||
{
|
||||
int Columns = Rows[Headder ? 3 : 0].count();
|
||||
QVector<int> ColumnWidths(Columns, 0);
|
||||
|
||||
foreach(const QStringList& Row, Rows)
|
||||
{
|
||||
for (int i = 0; i < Min(Row.count(), Columns); i++)
|
||||
{
|
||||
int CellWidth = Row[i].length();
|
||||
if (ColumnWidths[i] < CellWidth)
|
||||
ColumnWidths[i] = CellWidth;
|
||||
}
|
||||
}
|
||||
|
||||
foreach(const QStringList& Row, Rows)
|
||||
{
|
||||
if (m_MaxCellWidth != 0 && RowCount > 1)
|
||||
{
|
||||
for (int Pos = 0;;Pos += m_MaxCellWidth)
|
||||
{
|
||||
bool More = false;
|
||||
|
||||
QString RowText;
|
||||
for (int i = 0; i < Min(Row.count(), Columns); i++)
|
||||
{
|
||||
if (Row[i].length() > Pos)
|
||||
RowText.append(Row[i].mid(Pos, m_MaxCellWidth).leftJustified(Min(m_MaxCellWidth, ColumnWidths[i]) + 3));
|
||||
else
|
||||
RowText.append(QString(Min(m_MaxCellWidth, ColumnWidths[i]) + 3, ' '));
|
||||
|
||||
if (Row[i].length() > Pos + m_MaxCellWidth)
|
||||
More = true;
|
||||
}
|
||||
TextRows.append(RowText);
|
||||
|
||||
if (!More)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QString RowText;
|
||||
for (int i = 0; i < Min(Row.count(), Columns); i++)
|
||||
RowText.append(Row[i].leftJustified(ColumnWidths[i] + 3));
|
||||
TextRows.append(RowText);
|
||||
}
|
||||
}
|
||||
}
|
||||
QApplication::clipboard()->setText(TextRows.join("\n"));
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CPanelView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CPanelView(QWidget *parent = 0);
|
||||
virtual ~CPanelView();
|
||||
|
||||
static void SetSimpleFormat(bool bSimple) { m_SimpleFormat = bSimple; }
|
||||
static void SetMaxCellWidth(int iMaxWidth) { m_MaxCellWidth = iMaxWidth; }
|
||||
static void SetCellSeparator(const QString& Sep) { m_CellSeparator = Sep; }
|
||||
|
||||
protected slots:
|
||||
virtual void OnMenu(const QPoint& Point);
|
||||
|
||||
virtual void OnCopyCell();
|
||||
virtual void OnCopyRow();
|
||||
virtual void OnCopyPanel();
|
||||
|
||||
|
||||
virtual QTreeView* GetView() = 0;
|
||||
virtual QAbstractItemModel* GetModel() = 0;
|
||||
virtual QModelIndex MapToSource(const QModelIndex& Model) { return Model; }
|
||||
static QModelIndexList MapToSource(QModelIndexList Indexes, QSortFilterProxyModel* pProxy) {
|
||||
for (int i = 0; i < Indexes.count(); i++)
|
||||
Indexes[i] = pProxy->mapToSource(Indexes[i]);
|
||||
return Indexes;
|
||||
}
|
||||
|
||||
virtual void AddPanelItemsToMenu(bool bAddSeparator = true);
|
||||
|
||||
virtual void ForceColumn(int column, bool bSet = true) { if (bSet) m_ForcedColumns.insert(column); else m_ForcedColumns.remove(column); }
|
||||
|
||||
virtual QStringList CopyHeader();
|
||||
virtual QStringList CopyRow(const QModelIndex& ModelIndex, int Level = 0);
|
||||
virtual void RecursiveCopyPanel(const QModelIndex& ModelIndex, QList<QStringList>& Rows, int Level = 0);
|
||||
|
||||
protected:
|
||||
void FormatAndCopy(QList<QStringList> Rows, bool Headder = true);
|
||||
|
||||
QMenu* m_pMenu;
|
||||
|
||||
QAction* m_pCopyCell;
|
||||
QAction* m_pCopyRow;
|
||||
QAction* m_pCopyPanel;
|
||||
|
||||
//bool m_CopyAll;
|
||||
QSet<int> m_ForcedColumns;
|
||||
static bool m_SimpleFormat;
|
||||
static int m_MaxCellWidth;
|
||||
static QString m_CellSeparator;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class CPanelWidget : public CPanelView
|
||||
{
|
||||
public:
|
||||
CPanelWidget(QWidget *parent = 0) : CPanelView(parent)
|
||||
{
|
||||
m_pMainLayout = new QVBoxLayout();
|
||||
m_pMainLayout->setMargin(0);
|
||||
this->setLayout(m_pMainLayout);
|
||||
|
||||
m_pTreeList = new T();
|
||||
m_pTreeList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_pTreeList, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(OnMenu(const QPoint &)));
|
||||
m_pMainLayout->addWidget(m_pTreeList);
|
||||
m_pTreeList->setMinimumHeight(50);
|
||||
AddPanelItemsToMenu();
|
||||
|
||||
m_pLastAction = m_pMenu->actions()[0];
|
||||
}
|
||||
|
||||
virtual QMenu* GetMenu() { return m_pMenu; }
|
||||
virtual void AddAction(QAction* pAction) { m_pMenu->insertAction(m_pLastAction, pAction); }
|
||||
|
||||
virtual T* GetTree() { return m_pTreeList; }
|
||||
virtual QTreeView* GetView() { return m_pTreeList; }
|
||||
virtual QAbstractItemModel* GetModel() { return m_pTreeList->model(); }
|
||||
|
||||
protected:
|
||||
QVBoxLayout* m_pMainLayout;
|
||||
|
||||
T* m_pTreeList;
|
||||
|
||||
QAction* m_pLastAction;
|
||||
};
|
||||
|
||||
#include "TreeWidgetEx.h"
|
||||
#include "Finder.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CPanelWidgetEx : public CPanelWidget<QTreeWidgetEx>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CPanelWidgetEx(QWidget *parent = 0) : CPanelWidget<QTreeWidgetEx>(parent)
|
||||
{
|
||||
m_pFinder = new CFinder(NULL, this, false);
|
||||
m_pMainLayout->addWidget(m_pFinder);
|
||||
QObject::connect(m_pFinder, SIGNAL(SetFilter(const QRegExp&, bool, int)), this, SLOT(SetFilter(const QRegExp&, bool, int)));
|
||||
}
|
||||
|
||||
static void ApplyFilter(QTreeWidgetEx* pTree, QTreeWidgetItem* pItem, const QRegExp& Exp/*, bool bHighLight = false, int Col = -1*/)
|
||||
{
|
||||
for (int j = 0; j < pTree->columnCount(); j++)
|
||||
pItem->setBackground(j, !Exp.isEmpty() && pItem->text(j).contains(Exp) ? Qt::yellow : Qt::white);
|
||||
|
||||
for (int i = 0; i < pItem->childCount(); i++)
|
||||
{
|
||||
ApplyFilter(pTree, pItem->child(i), Exp/*, bHighLight, Col*/);
|
||||
}
|
||||
}
|
||||
|
||||
static void ApplyFilter(QTreeWidgetEx* pTree, const QRegExp& Exp/*, bool bHighLight = false, int Col = -1*/)
|
||||
{
|
||||
for (int i = 0; i < pTree->topLevelItemCount(); i++)
|
||||
ApplyFilter(pTree, pTree->topLevelItem(i), Exp/*, bHighLight, Col*/);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void SetFilter(const QRegExp& Exp, bool bHighLight = false, int Col = -1) // -1 = any
|
||||
{
|
||||
ApplyFilter(m_pTreeList, Exp);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
CFinder* m_pFinder;
|
||||
};
|
||||
|
||||
#include "TreeViewEx.h"
|
||||
|
||||
template <class T>
|
||||
class CPanelViewImpl: public CPanelWidget<QTreeViewEx>
|
||||
{
|
||||
public:
|
||||
CPanelViewImpl(T* pModel, QWidget *parent = 0) : CPanelWidget<QTreeViewEx>(parent)
|
||||
{
|
||||
m_pModel = pModel;
|
||||
|
||||
m_pSortProxy = new CSortFilterProxyModel(false, this);
|
||||
m_pSortProxy->setSortRole(Qt::EditRole);
|
||||
m_pSortProxy->setSourceModel(m_pModel);
|
||||
m_pSortProxy->setDynamicSortFilter(true);
|
||||
|
||||
m_pTreeList->setModel(m_pSortProxy);
|
||||
|
||||
m_pTreeList->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
#ifdef WIN32
|
||||
QStyle* pStyle = QStyleFactory::create("windows");
|
||||
m_pTreeList->setStyle(pStyle);
|
||||
#endif
|
||||
m_pTreeList->setSortingEnabled(true);
|
||||
|
||||
m_pTreeList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_pTreeList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnMenu(const QPoint &)));
|
||||
|
||||
m_pTreeList->setColumnReset(1);
|
||||
//connect(m_pTreeList, SIGNAL(ResetColumns()), m_pTreeList, SLOT(OnResetColumns()));
|
||||
//connect(m_pBoxTree, SIGNAL(ColumnChanged(int, bool)), this, SLOT(OnColumnsChanged()));
|
||||
}
|
||||
|
||||
protected:
|
||||
T* m_pModel;
|
||||
QSortFilterProxyModel* m_pSortProxy;
|
||||
};
|
|
@ -0,0 +1,117 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CProgressDialog : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CProgressDialog(const QString& Prompt, QWidget* parent = 0)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
setWindowFlags(Qt::Tool);
|
||||
|
||||
m_pMainWidget = new QWidget();
|
||||
m_pMainLayout = new QGridLayout(this);
|
||||
m_pMainWidget->setLayout(m_pMainLayout);
|
||||
this->setCentralWidget(m_pMainWidget);
|
||||
|
||||
m_pMessageLabel = new QLabel(Prompt);
|
||||
m_pMessageLabel->setMinimumWidth(300);
|
||||
m_pMessageLabel->setWordWrap(true);
|
||||
m_pMainLayout->addWidget(m_pMessageLabel, 0, 0, 1, 1);
|
||||
|
||||
m_pProgressBar = new QProgressBar();
|
||||
m_pProgressBar->setTextVisible(false);
|
||||
m_pProgressBar->setMaximum(0);
|
||||
m_pProgressBar->setMinimum(0);
|
||||
m_pMainLayout->addWidget(m_pProgressBar, 1, 0, 1, 1);
|
||||
|
||||
m_pButtonBox = new QDialogButtonBox();
|
||||
m_pButtonBox->setOrientation(Qt::Horizontal);
|
||||
m_pButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
|
||||
m_pMainLayout->addWidget(m_pButtonBox, 2, 0, 1, 1);
|
||||
|
||||
setFixedSize(sizeHint());
|
||||
|
||||
connect(m_pButtonBox,SIGNAL(rejected()),this,SIGNAL(Cancel()));
|
||||
|
||||
m_TimerId = startTimer(1000);
|
||||
m_CountDown = 0;
|
||||
}
|
||||
~CProgressDialog()
|
||||
{
|
||||
killTimer(m_TimerId);
|
||||
}
|
||||
|
||||
signals:
|
||||
void Cancel();
|
||||
|
||||
public slots:
|
||||
void OnProgressMessage(const QString& Message, int Progress = -1)
|
||||
{
|
||||
if(!Message.isEmpty())
|
||||
m_pMessageLabel->setText(Message);
|
||||
|
||||
if (Progress == -1)
|
||||
{
|
||||
if (m_pProgressBar->maximum() != 0)
|
||||
m_pProgressBar->setMinimum(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_pProgressBar->maximum() != 100)
|
||||
m_pProgressBar->setMinimum(100);
|
||||
|
||||
m_pProgressBar->setValue(Progress);
|
||||
}
|
||||
}
|
||||
|
||||
void OnStatusMessage(const QString& Message, int Code = 0)
|
||||
{
|
||||
//if(Code == 0)
|
||||
m_pMessageLabel->setText(Message);
|
||||
//else // note: parent can't be set as this window may auto close
|
||||
// QMessageBox::warning(NULL, this->windowTitle(), Message);
|
||||
}
|
||||
|
||||
void OnFinished()
|
||||
{
|
||||
m_pButtonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
|
||||
m_CountDown = 3;
|
||||
}
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if (e->timerId() != m_TimerId)
|
||||
{
|
||||
QMainWindow::timerEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_CountDown != 0)
|
||||
{
|
||||
m_CountDown--;
|
||||
m_pButtonBox->button(QDialogButtonBox::Cancel)->setText(tr("Close (%1)").arg(m_CountDown));
|
||||
if (m_CountDown == 0)
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void closeEvent(QCloseEvent *e)
|
||||
{
|
||||
emit Cancel();
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
int m_TimerId;
|
||||
int m_CountDown;
|
||||
|
||||
QWidget* m_pMainWidget;
|
||||
QGridLayout* m_pMainLayout;
|
||||
QLabel* m_pMessageLabel;
|
||||
QProgressBar* m_pProgressBar;
|
||||
QDialogButtonBox* m_pButtonBox;
|
||||
};
|
|
@ -0,0 +1,113 @@
|
|||
#include "stdafx.h"
|
||||
#include "Settings.h"
|
||||
//#include "qzlib.h"
|
||||
#include "Common.h"
|
||||
|
||||
bool TestWriteRight(const QString& Path)
|
||||
{
|
||||
QFile TestFile(Path + "/~test-" + GetRand64Str() + ".tmp");
|
||||
if(!TestFile.open(QFile::WriteOnly))
|
||||
return false;
|
||||
TestFile.close();
|
||||
return TestFile.remove();
|
||||
}
|
||||
|
||||
CSettings::CSettings(const QString& AppName, QMap<QString, SSetting> DefaultValues, QObject* qObject) : QObject(qObject)
|
||||
{
|
||||
m_ConfigDir = QCoreApplication::applicationDirPath();
|
||||
if (!(m_bPortable = QFile::exists(m_ConfigDir + "/" + AppName + ".ini")))
|
||||
{
|
||||
QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
|
||||
if (dirs.isEmpty())
|
||||
m_ConfigDir = QDir::homePath() + "/." + AppName;
|
||||
else
|
||||
m_ConfigDir = dirs.first() + "/" + AppName;
|
||||
QDir().mkpath(m_ConfigDir);
|
||||
}
|
||||
|
||||
m_pConf = new QSettings(m_ConfigDir + "/" + AppName + ".ini", QSettings::IniFormat, this);
|
||||
|
||||
m_pConf->sync();
|
||||
|
||||
m_DefaultValues = DefaultValues;
|
||||
foreach (const QString& Key, m_DefaultValues.uniqueKeys())
|
||||
{
|
||||
const SSetting& Setting = m_DefaultValues[Key];
|
||||
if(!m_pConf->contains(Key) || !Setting.Check(m_pConf->value(Key)))
|
||||
{
|
||||
if(Setting.IsBlob())
|
||||
m_pConf->setValue(Key, Setting.Value.toByteArray().toBase64().replace("+","-").replace("/","_").replace("=",""));
|
||||
else
|
||||
m_pConf->setValue(Key, Setting.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CSettings::~CSettings()
|
||||
{
|
||||
m_pConf->sync();
|
||||
}
|
||||
|
||||
bool CSettings::SetValue(const QString &key, const QVariant &value)
|
||||
{
|
||||
QMutexLocker Locker(&m_Mutex);
|
||||
|
||||
if (!m_DefaultValues.isEmpty())
|
||||
{
|
||||
ASSERT(m_pConf->contains(key));
|
||||
#ifndef _DEBUG
|
||||
if (!m_DefaultValues[key].Check(value))
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
m_pConf->setValue(key, value);
|
||||
|
||||
m_ValueCache.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariant CSettings::GetValue(const QString &key, const QVariant& preset)
|
||||
{
|
||||
QMutexLocker Locker(&m_Mutex);
|
||||
|
||||
ASSERT(m_DefaultValues.isEmpty() || m_pConf->contains(key));
|
||||
|
||||
return m_pConf->value(key, preset);
|
||||
}
|
||||
|
||||
void CSettings::SetBlob(const QString& key, const QByteArray& value)
|
||||
{
|
||||
QString str;
|
||||
//QByteArray data = Pack(value);
|
||||
//if(data.size() < value.size())
|
||||
// str = ":PackedArray:" + data.toBase64().replace("+","-").replace("/","_").replace("=","");
|
||||
//else
|
||||
str = ":ByteArray:" + value.toBase64().replace("+","-").replace("/","_").replace("=","");
|
||||
SetValue(key, str);
|
||||
}
|
||||
|
||||
QByteArray CSettings::GetBlob(const QString& key)
|
||||
{
|
||||
QByteArray value;
|
||||
QByteArray str = GetValue(key).toByteArray();
|
||||
if(str.left(11) == ":ByteArray:")
|
||||
value = QByteArray::fromBase64(str.mid(11).replace("-","+").replace("_","/"));
|
||||
//else if(str.left(13) == ":PackedArray:")
|
||||
// value = Unpack(QByteArray::fromBase64(str.mid(13).replace("-","+").replace("_","/")));
|
||||
return value;
|
||||
}
|
||||
|
||||
const QStringList CSettings::ListKeys(const QString& Root)
|
||||
{
|
||||
QMutexLocker Locker(&m_Mutex);
|
||||
QStringList Keys;
|
||||
foreach(const QString& Key, m_pConf->allKeys())
|
||||
{
|
||||
QStringList Path = Key.split("/");
|
||||
ASSERT(Path.count() == 2);
|
||||
if(Path[0] == Root)
|
||||
Keys.append(Path[1]);
|
||||
}
|
||||
return Keys;
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
#pragma once
|
||||
|
||||
#include <QSettings>
|
||||
#include <QVariant>
|
||||
#include <QMutex>
|
||||
#include <QStringList>
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CSettings: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct SStrRef
|
||||
{
|
||||
SStrRef(const char* pRef)
|
||||
: Ref(pRef) {}
|
||||
|
||||
bool operator < (const SStrRef& Other) const {return strcmp(Ref, Other.Ref) < 0;}
|
||||
bool operator == (const SStrRef& Other) const {return strcmp(Ref, Other.Ref) == 0;}
|
||||
|
||||
operator QString() const {return QString(Ref);}
|
||||
|
||||
const char* Ref;
|
||||
};
|
||||
|
||||
union SCacheVal
|
||||
{
|
||||
bool _Bool;
|
||||
qint32 _Int;
|
||||
quint32 _UInt;
|
||||
quint64 _UInt64;
|
||||
};
|
||||
|
||||
struct SSetting
|
||||
{
|
||||
SSetting(){
|
||||
MinValue = 0;
|
||||
MaxValue = 0;
|
||||
}
|
||||
|
||||
SSetting(const QVariant& value){
|
||||
Value = value;
|
||||
MinValue = 0;
|
||||
MaxValue = 0;
|
||||
}
|
||||
|
||||
SSetting(qint64 value, qint64 minvalue = LLONG_MIN, qint64 maxvalue = LLONG_MAX) {
|
||||
Value = value;
|
||||
MinValue = minvalue;
|
||||
MaxValue = maxvalue;
|
||||
}
|
||||
|
||||
SSetting(const QString& value, const QStringList& values) {
|
||||
Value = value;
|
||||
MinValue = 0;
|
||||
MaxValue = 0;
|
||||
Values = values;
|
||||
}
|
||||
|
||||
bool Check(const QVariant& value) const
|
||||
{
|
||||
if(MinValue != MaxValue)
|
||||
{
|
||||
if(!value.canConvert(QVariant::LongLong))
|
||||
return false;
|
||||
qint64 Test = value.toLongLong();
|
||||
if(Test < MinValue || MinValue > MaxValue)
|
||||
return false;
|
||||
}
|
||||
else if(!Values.isEmpty())
|
||||
{
|
||||
if(!value.canConvert(QVariant::String))
|
||||
return false;
|
||||
if(!Values.contains(value.toString()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool IsBlob() const {return false;}
|
||||
|
||||
QVariant Value;
|
||||
qint64 MinValue;
|
||||
qint64 MaxValue;
|
||||
QStringList Values;
|
||||
};
|
||||
|
||||
struct SBlobSetting: SSetting
|
||||
{
|
||||
SBlobSetting(const QByteArray& value){
|
||||
Value = value;
|
||||
MinValue = 0;
|
||||
MaxValue = 0;
|
||||
}
|
||||
virtual bool IsBlob() const {return true;}
|
||||
};
|
||||
|
||||
CSettings(const QString& AppName, QMap<QString, SSetting> DefaultValues = QMap<QString, SSetting>(), QObject* qObject = NULL);
|
||||
virtual ~CSettings();
|
||||
|
||||
bool SetValue(const QString& key, const QVariant& value);
|
||||
QVariant GetValue(const QString& key, const QVariant& preset = QVariant());
|
||||
|
||||
void SetBlob(const QString& key, const QByteArray& value);
|
||||
QByteArray GetBlob(const QString& key);
|
||||
|
||||
#define IMPL_CFG_CACHE_GET(x,y,z) \
|
||||
x Get##y(const SStrRef& key, x def = 0) \
|
||||
{ \
|
||||
QMutexLocker Locker(&m_Mutex); \
|
||||
QMap<SStrRef, SCacheVal>::Iterator I = m_ValueCache.find(key); \
|
||||
if(I != m_ValueCache.end()) \
|
||||
return I.value()._##y; \
|
||||
Locker.unlock(); \
|
||||
x val = GetValue(key, def).to##z(); \
|
||||
Locker.relock(); \
|
||||
SCacheVal entry; \
|
||||
entry._##y = val; \
|
||||
m_ValueCache.insert(key, entry); \
|
||||
return val; \
|
||||
}
|
||||
IMPL_CFG_CACHE_GET(bool, Bool, Bool);
|
||||
IMPL_CFG_CACHE_GET(qint32, Int, Int);
|
||||
IMPL_CFG_CACHE_GET(quint32, UInt, UInt);
|
||||
IMPL_CFG_CACHE_GET(quint64, UInt64, ULongLong);
|
||||
#undef IMPL_CFG_CACHE_GET
|
||||
|
||||
const QString GetString(const QString& key, const QVariant& preset = QVariant()) {return GetValue(key, preset).toString();}
|
||||
const QStringList GetStringList(const QString& key, const QVariant& preset = QVariant()) {return GetValue(key, preset).toStringList();}
|
||||
|
||||
const QStringList ListSettings() {QMutexLocker Locker(&m_Mutex); return m_pConf->allKeys();}
|
||||
const QStringList ListGroupes() {QMutexLocker Locker(&m_Mutex); return m_pConf->childGroups();}
|
||||
const QStringList ListKeys(const QString& Root);
|
||||
|
||||
const QString GetConfigDir() {QMutexLocker Locker(&m_Mutex); return m_ConfigDir;}
|
||||
const bool IsPortable() {QMutexLocker Locker(&m_Mutex); return m_bPortable;}
|
||||
|
||||
protected:
|
||||
QMutex m_Mutex;
|
||||
QMap<QString, SSetting> m_DefaultValues;
|
||||
|
||||
QMap<SStrRef, SCacheVal>m_ValueCache;
|
||||
|
||||
QString m_ConfigDir;
|
||||
bool m_bPortable;
|
||||
|
||||
QSettings* m_pConf;
|
||||
};
|
|
@ -0,0 +1,70 @@
|
|||
#include "stdafx.h"
|
||||
#include "SettingsWidgets.h"
|
||||
#include "CheckableMessageBox.h"
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// CPathEdit
|
||||
|
||||
CPathEdit::CPathEdit(bool bDirs, QWidget *parent)
|
||||
: CTxtEdit(parent)
|
||||
{
|
||||
m_bDirs = bDirs;
|
||||
|
||||
QHBoxLayout* pLayout = new QHBoxLayout(this);
|
||||
pLayout->setMargin(0);
|
||||
m_pEdit = new QLineEdit(this);
|
||||
connect(m_pEdit, SIGNAL(textChanged(const QString &)), this, SIGNAL(textChanged(const QString &)));
|
||||
pLayout->addWidget(m_pEdit);
|
||||
QPushButton* pButton = new QPushButton("...");
|
||||
pButton->setMaximumWidth(25);
|
||||
connect(pButton, SIGNAL(pressed()), this, SLOT(Browse()));
|
||||
pLayout->addWidget(pButton);
|
||||
}
|
||||
|
||||
void CPathEdit::Browse()
|
||||
{
|
||||
QString FilePath = m_bDirs
|
||||
? QFileDialog::getExistingDirectory(this, tr("Select Directory"))
|
||||
: QFileDialog::getOpenFileName(0, tr("Browse"), "", QString("Any File (*.*)"));
|
||||
if(!FilePath.isEmpty())
|
||||
SetText(FilePath);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// CProxyEdit
|
||||
|
||||
CProxyEdit::CProxyEdit(QWidget *parent)
|
||||
: CTxtEdit(parent)
|
||||
{
|
||||
QHBoxLayout* pLayout = new QHBoxLayout(this);
|
||||
pLayout->setMargin(0);
|
||||
|
||||
m_pType = new QComboBox();
|
||||
m_pType->addItem(QString("No"));
|
||||
m_pType->addItem(QString("http"));
|
||||
m_pType->addItem(QString("socks5"));
|
||||
connect(m_pType, SIGNAL(activated(int)), this, SLOT(OnType(int)));
|
||||
pLayout->addWidget(m_pType);
|
||||
|
||||
m_pEdit = new QLineEdit(this);
|
||||
connect(m_pEdit, SIGNAL(textChanged(const QString &)), this, SIGNAL(textChanged(const QString &)));
|
||||
pLayout->addWidget(m_pEdit);
|
||||
}
|
||||
|
||||
void CProxyEdit::SetText(const QString& Text)
|
||||
{
|
||||
QUrl Url(Text);
|
||||
m_pType->setCurrentText(Url.scheme());
|
||||
m_pEdit->setText(Text);
|
||||
}
|
||||
|
||||
void CProxyEdit::OnType(int Index)
|
||||
{
|
||||
if(Index == 0)
|
||||
m_pEdit->setEnabled(false);
|
||||
else
|
||||
{
|
||||
m_pEdit->setEnabled(true);
|
||||
m_pEdit->setText(m_pType->currentText() + "://");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,421 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CMultiLineEdit: public QPlainTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CMultiLineEdit(QWidget *parent = 0)
|
||||
:QPlainTextEdit(parent) {}
|
||||
|
||||
void SetLines(const QStringList& Lines){
|
||||
setPlainText(Lines.join("\r\n"));
|
||||
}
|
||||
QStringList GetLines(){
|
||||
return toPlainText().split(QRegExp("\r?\n"));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
class MISCHELPERS_EXPORT QNumEdit: public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(int Value READ GetValue WRITE SetValue)
|
||||
|
||||
public:
|
||||
QNumEdit(QWidget *parent = 0) : QLineEdit(parent) {}
|
||||
|
||||
virtual void SetValue(qint64 Value) = 0;
|
||||
virtual qint64 GetValue() = 0;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
class MISCHELPERS_EXPORT CKbpsEdit: public QNumEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CKbpsEdit(qint64 Factor = 1024, QWidget *parent = 0)
|
||||
:QNumEdit(parent) , m_Factor(Factor) {}
|
||||
|
||||
void SetValue(qint64 Value){
|
||||
if(Value <= 0)
|
||||
setText(tr("Unlimited"));
|
||||
else
|
||||
setText(QString::number(Value/m_Factor));
|
||||
}
|
||||
qint64 GetValue(){
|
||||
int Value = text().toInt();
|
||||
if(Value > 0)
|
||||
return Value*m_Factor;
|
||||
else
|
||||
return -1; // Unlimited;
|
||||
}
|
||||
|
||||
protected:
|
||||
qint64 m_Factor;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
class MISCHELPERS_EXPORT CFactorEdit: public QNumEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CFactorEdit(double Factor = 100.0, int Prec = 2, bool bEmpty = false, QWidget *parent = 0)
|
||||
:QNumEdit(parent), m_Factor(Factor), m_Empty(bEmpty), m_Prec(Prec) {}
|
||||
|
||||
void SetValue(qint64 Value){
|
||||
if(!Value && m_Empty)
|
||||
setText("");
|
||||
else
|
||||
setText(QString::number(Value / m_Factor, 'f', m_Prec));
|
||||
}
|
||||
qint64 GetValue(){
|
||||
return text().toDouble() * m_Factor;
|
||||
}
|
||||
|
||||
protected:
|
||||
double m_Factor;
|
||||
bool m_Empty;
|
||||
int m_Prec;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
class MISCHELPERS_EXPORT CSpinBoxEx: public QSpinBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CSpinBoxEx(quint64 Unit, QWidget *parent = 0)
|
||||
:QSpinBox(parent) {
|
||||
m_Unit = Unit;
|
||||
setSingleStep(Unit);
|
||||
setMaximum(INT_MAX);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int valueFromText(const QString &text) const{
|
||||
return text.toInt() * m_Unit;
|
||||
}
|
||||
virtual QString textFromValue(int val) const{
|
||||
return QString::number(val / m_Unit);
|
||||
}
|
||||
|
||||
quint64 m_Unit;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
class MISCHELPERS_EXPORT CTxtEdit: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString Data READ GetText WRITE SetText)
|
||||
|
||||
public:
|
||||
CTxtEdit(QWidget *parent = 0) : QWidget(parent) {}
|
||||
|
||||
virtual void SetText(const QString& Text) = 0;
|
||||
virtual QString GetText() = 0;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// CPathEdit
|
||||
|
||||
class MISCHELPERS_EXPORT CPathEdit: public CTxtEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CPathEdit(bool bDirs = false, QWidget *parent = 0);
|
||||
|
||||
QLineEdit* GetEdit() {return m_pEdit;}
|
||||
|
||||
void SetText(const QString& Text) {m_pEdit->setText(Text);}
|
||||
QString GetText() {return m_pEdit->text();}
|
||||
|
||||
signals:
|
||||
void textChanged(const QString& text);
|
||||
|
||||
private slots:
|
||||
void Browse();
|
||||
protected:
|
||||
QLineEdit* m_pEdit;
|
||||
bool m_bDirs;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// CProxyEdit
|
||||
|
||||
class MISCHELPERS_EXPORT CProxyEdit: public CTxtEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CProxyEdit(QWidget *parent = 0);
|
||||
|
||||
void SetText(const QString& Text);
|
||||
QString GetText() {return m_pEdit->text();}
|
||||
|
||||
signals:
|
||||
void textChanged(const QString& text);
|
||||
|
||||
private slots:
|
||||
void OnType(int Index);
|
||||
|
||||
protected:
|
||||
QComboBox* m_pType;
|
||||
QLineEdit* m_pEdit;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
class MISCHELPERS_EXPORT QComboBoxEx: public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QVariant Data READ GetData)
|
||||
|
||||
public:
|
||||
QComboBoxEx(QWidget* pParent = 0) : QComboBox(pParent) {}
|
||||
|
||||
QVariant GetData() {return itemData(currentIndex());}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
class MISCHELPERS_EXPORT QCheckBoxEx: public QCheckBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QCheckBoxEx(const QString& Text, bool bSwap = true) : QCheckBox(Text)
|
||||
{
|
||||
m_bSwap = bSwap;
|
||||
setTristate();
|
||||
}
|
||||
|
||||
void SetState(int State)
|
||||
{
|
||||
if(m_bSwap)
|
||||
{
|
||||
switch(State)
|
||||
{
|
||||
case 0: State = Qt::PartiallyChecked; break;
|
||||
case 1: State = Qt::Checked; break;
|
||||
case 2: State = Qt::Unchecked; break;
|
||||
}
|
||||
}
|
||||
setCheckState((Qt::CheckState)State);
|
||||
}
|
||||
|
||||
int GetState()
|
||||
{
|
||||
int State = checkState();
|
||||
if(m_bSwap)
|
||||
{
|
||||
switch(State)
|
||||
{
|
||||
case Qt::PartiallyChecked: State = 0; break;
|
||||
case Qt::Checked: State = 1; break;
|
||||
case Qt::Unchecked: State = 2; break;
|
||||
}
|
||||
}
|
||||
return State;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_bSwap;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
class MISCHELPERS_EXPORT QSecretCheckBox: public QCheckBoxEx
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QSecretCheckBox(const QString& Text) : QCheckBoxEx(Text, false)
|
||||
{
|
||||
setTristate(false);
|
||||
}
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent (QMouseEvent * e)
|
||||
{
|
||||
if(QApplication::keyboardModifiers() & Qt::ControlModifier)
|
||||
setTristate();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// QSpinBoxEx
|
||||
|
||||
class MISCHELPERS_EXPORT QSpinBoxEx: public QSpinBox
|
||||
{
|
||||
public:
|
||||
QSpinBoxEx(QWidget* parent, const QString& Default, const QString& Suffix = "", bool exponential = false) : QSpinBox(parent)
|
||||
{
|
||||
m_default = 1;
|
||||
|
||||
setRange(0, INT_MAX);
|
||||
setSuffix(Suffix);
|
||||
setSpecialValueText(Default + Suffix);
|
||||
m_exponential = exponential;
|
||||
}
|
||||
|
||||
void stepBy(int steps)
|
||||
{
|
||||
if(m_exponential)
|
||||
{
|
||||
int Value = value();
|
||||
if(!Value)
|
||||
{
|
||||
Value = m_default;
|
||||
if(Value <= 0)
|
||||
Value = 1;
|
||||
}
|
||||
|
||||
if(steps == 1)
|
||||
setValue(Value*2);
|
||||
else if(steps == -1)
|
||||
setValue(Value/2);
|
||||
else
|
||||
QSpinBox::stepBy(steps);
|
||||
}
|
||||
else
|
||||
QSpinBox::stepBy(steps);
|
||||
}
|
||||
|
||||
void setDefault(int value) {m_default = value;}
|
||||
|
||||
protected:
|
||||
int m_default;
|
||||
bool m_exponential;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// CMenuAction & CActionWidget
|
||||
|
||||
class MISCHELPERS_EXPORT QMenu_: public QMenu { public: void initStyleOption_(QStyleOptionMenuItem *option, const QAction *action) const {QMenu::initStyleOption(option, action);} };
|
||||
|
||||
|
||||
class MISCHELPERS_EXPORT CActionWidget: public QWidget
|
||||
{
|
||||
public:
|
||||
CActionWidget(QWidget* parent = 0) : QWidget(parent) {}
|
||||
|
||||
void paintEvent(QPaintEvent* e)
|
||||
{
|
||||
QPainter p(this);
|
||||
|
||||
QMenu_ Menu;
|
||||
QAction* action = new QAction(this);
|
||||
|
||||
QStyleOptionMenuItem opt;
|
||||
Menu.initStyleOption_(&opt, action);
|
||||
opt.menuRect = opt.rect = QRect(0, 0, 22, 22); // with this icons and text are drown properly
|
||||
style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);
|
||||
}
|
||||
};
|
||||
|
||||
class MISCHELPERS_EXPORT CMenuAction: public QWidgetAction
|
||||
{
|
||||
public:
|
||||
CMenuAction (QWidget* pControll, const QString& Title, QString IconFile = "") : QWidgetAction (pControll->parent())
|
||||
{
|
||||
QWidget* pWidget = new CActionWidget(pControll->parentWidget());
|
||||
QHBoxLayout* pLayout = new QHBoxLayout();
|
||||
pLayout->setMargin(0);
|
||||
|
||||
if(!IconFile.isEmpty())
|
||||
{
|
||||
QImage Image(IconFile);
|
||||
QLabel* pIcon = new QLabel();
|
||||
pIcon->setToolTip(Title);
|
||||
pIcon->setPixmap(QPixmap::fromImage(Image).scaled(16,16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
pLayout->addWidget(pIcon);
|
||||
|
||||
pLayout->insertSpacing(0, 3);
|
||||
pLayout->insertSpacing(2, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
pLayout->addWidget(new QLabel(Title));
|
||||
|
||||
pLayout->insertSpacing(0, 32);
|
||||
}
|
||||
|
||||
pLayout->addWidget(pControll);
|
||||
|
||||
pWidget->setLayout(pLayout);
|
||||
setDefaultWidget(pWidget);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// QCheckComboBox
|
||||
|
||||
class MISCHELPERS_EXPORT QCheckComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QCheckComboBox()
|
||||
{
|
||||
view()->viewport()->installEventFilter(this);
|
||||
}
|
||||
|
||||
virtual bool eventFilter(QObject *watched, QEvent *e)
|
||||
{
|
||||
switch (e->type())
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
break;
|
||||
case QEvent::MouseButtonRelease:
|
||||
QMouseEvent *m = static_cast<QMouseEvent *>(e);
|
||||
|
||||
// is check box rect pressed
|
||||
if (m->localPos().x() < this->height())
|
||||
{
|
||||
QStandardItemModel *model_ = qobject_cast<QStandardItemModel *>(model());
|
||||
Qt::CheckState state = model_->data(view()->currentIndex(), Qt::CheckStateRole).value<Qt::CheckState>();
|
||||
|
||||
if (state != Qt::Checked)
|
||||
state = Qt::Checked;
|
||||
else
|
||||
state = Qt::Unchecked;
|
||||
|
||||
model_->setData(view()->currentIndex(), state, Qt::CheckStateRole);
|
||||
|
||||
emit checkStateChanged(view()->currentIndex().row(), state);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*if (isVisible() && view()->rect().contains(m->pos()) && view()->currentIndex().isValid()
|
||||
&& (view()->currentIndex().flags() & Qt::ItemIsEnabled)
|
||||
&& (view()->currentIndex().flags() & Qt::ItemIsSelectable)) {
|
||||
this->hidePopup();
|
||||
this->setCurrentIndex(view()->currentIndex().row());
|
||||
return true;
|
||||
}*/
|
||||
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
signals:
|
||||
void checkStateChanged(int Index, Qt::CheckState state);
|
||||
};
|
|
@ -0,0 +1,65 @@
|
|||
#include "stdafx.h"
|
||||
#include "SmartGridWidget.h"
|
||||
#include <math.h>
|
||||
|
||||
CSmartGridWidget::CSmartGridWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_pMainLayout = new QGridLayout();
|
||||
this->setLayout(m_pMainLayout);
|
||||
|
||||
m_pMainLayout->setMargin(1);
|
||||
m_pMainLayout->setSpacing(2);
|
||||
|
||||
m_bReArangePending = false;
|
||||
}
|
||||
|
||||
void CSmartGridWidget::SetBackground(const QColor& BackColor)
|
||||
{
|
||||
QPalette pal = palette();
|
||||
pal.setColor(QPalette::Background, BackColor);
|
||||
this->setAutoFillBackground(true);
|
||||
this->setPalette(pal);
|
||||
}
|
||||
|
||||
void CSmartGridWidget::AddWidget(QWidget* pWidget)
|
||||
{
|
||||
m_Widgets.append(pWidget);
|
||||
if(!pWidget->parent())
|
||||
pWidget->setParent(this);
|
||||
|
||||
if (!m_bReArangePending)
|
||||
{
|
||||
m_bReArangePending = true;
|
||||
QTimer::singleShot(0, this, SLOT(ReArange()));
|
||||
}
|
||||
}
|
||||
|
||||
void CSmartGridWidget::ReArange()
|
||||
{
|
||||
m_bReArangePending = false;
|
||||
|
||||
int count = 0;
|
||||
while (count < m_Widgets.size())
|
||||
{
|
||||
if (m_Widgets[count] == NULL)
|
||||
m_Widgets.removeAt(count);
|
||||
else
|
||||
count++;
|
||||
}
|
||||
|
||||
float columns = ceil(sqrt((float)count));
|
||||
float rows = columns > 0 ? ceil(count / columns) : 0;
|
||||
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
for (int column = 0; column < columns; column++)
|
||||
{
|
||||
int index = row * columns + column;
|
||||
if (index >= count)
|
||||
break;
|
||||
|
||||
m_pMainLayout->addWidget(m_Widgets.at(index), row, column);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
#include <qwidget.h>
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CSmartGridWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CSmartGridWidget(QWidget* parent = NULL);
|
||||
virtual ~CSmartGridWidget() {}
|
||||
|
||||
virtual void SetBackground(const QColor& BackColor);
|
||||
|
||||
virtual void AddWidget(QWidget* pWidget);
|
||||
|
||||
virtual int GetCount() { return m_Widgets.count(); }
|
||||
virtual QWidget* GetWidget(int Index) { return m_Widgets.at(Index); }
|
||||
|
||||
public slots:
|
||||
virtual void ReArange();
|
||||
|
||||
protected:
|
||||
QGridLayout* m_pMainLayout;
|
||||
|
||||
QList<QPointer<QWidget>>m_Widgets;
|
||||
|
||||
bool m_bReArangePending;
|
||||
};
|
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CSortFilterProxyModel: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CSortFilterProxyModel(bool bAlternate, QObject* parrent = 0) : QSortFilterProxyModel(parrent)
|
||||
{
|
||||
m_bAlternate = bAlternate;
|
||||
m_bHighLight = false;
|
||||
}
|
||||
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
|
||||
{
|
||||
if (m_bHighLight)
|
||||
return true;
|
||||
|
||||
// allow the item to pass if any of the child items pass
|
||||
if(!filterRegExp().isEmpty())
|
||||
{
|
||||
// get source-model index for current row
|
||||
QModelIndex source_index = sourceModel()->index(source_row, 0, source_parent);
|
||||
if(source_index.isValid())
|
||||
{
|
||||
// if any of children matches the filter, then current index matches the filter as well
|
||||
int nb = sourceModel()->rowCount(source_index);
|
||||
for(int i = 0; i < nb; i++)
|
||||
{
|
||||
if(filterAcceptsRow(i, source_index))
|
||||
return true;
|
||||
}
|
||||
// check current index itself
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
}
|
||||
}
|
||||
|
||||
// default behavioure
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
}
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QVariant Data = QSortFilterProxyModel::data(index, role);
|
||||
if (role == Qt::BackgroundRole)
|
||||
{
|
||||
if (m_bHighLight)
|
||||
{
|
||||
if (!filterRegExp().isEmpty())
|
||||
{
|
||||
QString Key = QSortFilterProxyModel::data(index, filterRole()).toString();
|
||||
if (Key.contains(filterRegExp()))
|
||||
return QColor(Qt::yellow);
|
||||
}
|
||||
return QColor(Qt::white);
|
||||
}
|
||||
|
||||
if (m_bAlternate && !Data.isValid())
|
||||
{
|
||||
if (0 == index.row() % 2)
|
||||
return QColor(226, 237, 253);
|
||||
else
|
||||
return QColor(Qt::white);
|
||||
}
|
||||
}
|
||||
return Data;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void SetFilter(const QRegExp& Exp, bool bHighLight = false, int Col = -1) // -1 = any
|
||||
{
|
||||
m_bHighLight = bHighLight;
|
||||
setFilterKeyColumn(Col);
|
||||
setFilterRegExp(Exp);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_bAlternate;
|
||||
bool m_bHighLight;
|
||||
};
|
|
@ -0,0 +1,369 @@
|
|||
#include "stdafx.h"
|
||||
#include "SplitTreeView.h"
|
||||
|
||||
CSplitTreeView::CSplitTreeView(QAbstractItemModel* pModel, QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
m_pModel = pModel;
|
||||
|
||||
m_pMainLayout = new QHBoxLayout();
|
||||
m_pMainLayout->setMargin(0);
|
||||
this->setLayout(m_pMainLayout);
|
||||
|
||||
|
||||
m_pSplitter = new QSplitter();
|
||||
m_pSplitter->setOrientation(Qt::Horizontal);
|
||||
m_pMainLayout->addWidget(m_pSplitter);
|
||||
|
||||
#ifdef WIN32
|
||||
QStyle* pStyle = QStyleFactory::create("windows");
|
||||
#endif
|
||||
|
||||
m_LockSellection = 0;
|
||||
|
||||
// Tree
|
||||
m_pTree = new QTreeView();
|
||||
|
||||
m_pOneModel = new COneColumnModel();
|
||||
m_pOneModel->setSourceModel(m_pModel);
|
||||
m_pTree->setModel(m_pOneModel);
|
||||
//m_pTree->setModel(m_pSortProxy);
|
||||
|
||||
m_pTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
#ifdef WIN32
|
||||
m_pTree->setStyle(pStyle);
|
||||
#endif
|
||||
//m_pTree->setSortingEnabled(true);
|
||||
m_pTree->setSortingEnabled(false);
|
||||
m_pTree->setUniformRowHeights(true);
|
||||
m_pTree->header()->setSortIndicatorShown(true);
|
||||
m_pTree->header()->setSectionsClickable(true);
|
||||
connect(m_pTree->header(), SIGNAL(sectionClicked(int)), this, SLOT(OnTreeCustomSortByColumn(int)));
|
||||
|
||||
m_pTree->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_pTree, SIGNAL(customContextMenuRequested( const QPoint& )), this, SIGNAL(MenuRequested(const QPoint &)));
|
||||
|
||||
m_pSplitter->addWidget(m_pTree);
|
||||
//m_pSplitter->setCollapsible(0, false);
|
||||
m_pSplitter->setStretchFactor(0, 0);
|
||||
//
|
||||
|
||||
|
||||
// List
|
||||
// Note: It would be convinient to use QTreeViewEx here but qt does not scale well when there are too many columns
|
||||
// hence we will add and remove columns at the model level directly.
|
||||
// This way we can get out operational CPU usage to be quite comparable with TaskInfo na other advanced task managers
|
||||
// Plus there are to many columns to cram them into one simple context menu :-)
|
||||
//m_pList = new QTreeViewEx();
|
||||
m_pList = new QTreeView();
|
||||
|
||||
m_pList->setModel(m_pModel);
|
||||
|
||||
m_pList->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
#ifdef WIN32
|
||||
m_pList->setStyle(pStyle);
|
||||
#endif
|
||||
m_pList->setSortingEnabled(true);
|
||||
m_pList->setUniformRowHeights(true);
|
||||
connect(m_pList->header(), SIGNAL(sectionClicked(int)), this, SLOT(OnListCustomSortByColumn(int)));
|
||||
|
||||
m_pList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_pList, SIGNAL(customContextMenuRequested( const QPoint& )), this, SIGNAL(MenuRequested(const QPoint &)));
|
||||
|
||||
m_pSplitter->addWidget(m_pList);
|
||||
m_pSplitter->setCollapsible(1, false);
|
||||
m_pSplitter->setStretchFactor(1, 1);
|
||||
//
|
||||
|
||||
connect(m_pSplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(OnSplitterMoved(int,int)));
|
||||
|
||||
// Link selections
|
||||
//m_pTree->setSelectionModel(m_pList->selectionModel()); // this works only when booth views share the same data model
|
||||
|
||||
connect(m_pTree->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(OnTreeSelectionChanged(QItemSelection,QItemSelection)));
|
||||
connect(m_pList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(OnListSelectionChanged(QItemSelection,QItemSelection)));
|
||||
|
||||
connect(m_pTree->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnTreeCurrentChanged(QModelIndex,QModelIndex)));
|
||||
connect(m_pList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnListCurrentChanged(QModelIndex,QModelIndex)));
|
||||
|
||||
m_bTreeEnabled = true;
|
||||
m_pList->setColumnHidden(0, true);
|
||||
|
||||
// link expansion
|
||||
connect(m_pTree, SIGNAL(expanded(const QModelIndex)), this, SLOT(OnExpandTree(const QModelIndex)));
|
||||
connect(m_pTree, SIGNAL(collapsed(const QModelIndex)), this, SLOT(OnCollapseTree(const QModelIndex)));
|
||||
//connect(m_pList, SIGNAL(expanded(const QModelIndex)), this, SLOT(expand(const QModelIndex)));
|
||||
//connect(m_pList, SIGNAL(collapsed(const QModelIndex)), this, SLOT(collapse(const QModelIndex)));
|
||||
|
||||
// link scrollbars
|
||||
m_pTree->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_pTree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
m_pList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
connect(m_pList->verticalScrollBar(), SIGNAL(valueChanged(int)), m_pTree->verticalScrollBar(), SLOT(setValue(int)));
|
||||
connect(m_pTree->verticalScrollBar(), SIGNAL(valueChanged(int)), m_pList->verticalScrollBar(), SLOT(setValue(int)));
|
||||
|
||||
connect(m_pTree, SIGNAL(clicked(const QModelIndex&)), this, SLOT(OnClickedTree(const QModelIndex&)));
|
||||
connect(m_pList, SIGNAL(clicked(const QModelIndex&)), this, SIGNAL(clicked(const QModelIndex&)));
|
||||
|
||||
connect(m_pTree, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(OnDoubleClickedTree(const QModelIndex&)));
|
||||
connect(m_pList, SIGNAL(doubleClicked(const QModelIndex&)), this, SIGNAL(doubleClicked(const QModelIndex&)));
|
||||
|
||||
//QTimer::singleShot(0, this, [this]() {
|
||||
// emit TreeEnabled(m_bTreeEnabled);
|
||||
//});
|
||||
}
|
||||
|
||||
CSplitTreeView::~CSplitTreeView()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CSplitTreeView::GetTreeWidth() const
|
||||
{
|
||||
QList<int> sizes = m_pSplitter->sizes();
|
||||
return sizes[0];
|
||||
}
|
||||
|
||||
void CSplitTreeView::SetTreeWidth(int Width)
|
||||
{
|
||||
QList<int> sizes = m_pSplitter->sizes();
|
||||
int total = sizes[0] + sizes[1];
|
||||
sizes[0] = Width;
|
||||
sizes[1] = total - Width;
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnSplitterMoved(int pos, int index)
|
||||
{
|
||||
if (index != 1)
|
||||
return;
|
||||
|
||||
//if ((pos > 0) == m_bTreeEnabled)
|
||||
// return;
|
||||
//m_bTreeEnabled = (pos > 0);
|
||||
|
||||
m_pList->setColumnHidden(0, pos > 0);
|
||||
|
||||
//emit TreeEnabled(m_bTreeEnabled);
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnExpandTree(const QModelIndex& index)
|
||||
{
|
||||
m_pList->expand(m_pOneModel->mapToSource(index));
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnCollapseTree(const QModelIndex& index)
|
||||
{
|
||||
m_pList->collapse(m_pOneModel->mapToSource(index));
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnClickedTree(const QModelIndex& Index)
|
||||
{
|
||||
emit clicked(m_pOneModel->mapToSource(Index));
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnDoubleClickedTree(const QModelIndex& Index)
|
||||
{
|
||||
emit doubleClicked(m_pOneModel->mapToSource(Index));
|
||||
}
|
||||
|
||||
void CSplitTreeView::expand(const QModelIndex &index)
|
||||
{
|
||||
m_pTree->expand(m_pOneModel->mapFromSource(index));
|
||||
}
|
||||
|
||||
void CSplitTreeView::collapse(const QModelIndex &index)
|
||||
{
|
||||
m_pTree->collapse(m_pOneModel->mapFromSource(index));
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnTreeSelectionChanged(const QItemSelection& Selected, const QItemSelection& Deselected)
|
||||
{
|
||||
if (m_LockSellection)
|
||||
return;
|
||||
m_LockSellection = 1;
|
||||
QItemSelection SelectedItems;
|
||||
foreach(const QModelIndex& Index, m_pTree->selectionModel()->selectedIndexes())
|
||||
{
|
||||
QModelIndex ModelIndex = m_pOneModel->mapToSource(Index);
|
||||
|
||||
QModelIndex ModelL = m_pModel->index(ModelIndex.row(), 0, ModelIndex.parent());
|
||||
QModelIndex ModelR = m_pModel->index(ModelIndex.row(), m_pModel->columnCount()-1, ModelIndex.parent());
|
||||
|
||||
SelectedItems.append(QItemSelectionRange(ModelL, ModelR));
|
||||
}
|
||||
m_pList->selectionModel()->select(SelectedItems, QItemSelectionModel::ClearAndSelect);
|
||||
/*
|
||||
foreach(const QModelIndex& Index, Selected.indexes())
|
||||
{
|
||||
QModelIndex ModelIndex = m_pOneModel->mapToSource(Index);
|
||||
|
||||
QModelIndex ModelL = m_pModel->index(ModelIndex.row(), 0, ModelIndex.parent());
|
||||
QModelIndex ModelR = m_pModel->index(ModelIndex.row(), m_pModel->columnCount()-1, ModelIndex.parent());
|
||||
|
||||
m_pList->selectionModel()->select(QItemSelection(ModelL, ModelR), QItemSelectionModel::Select);
|
||||
}
|
||||
foreach(const QModelIndex& Index, Deselected.indexes())
|
||||
{
|
||||
QModelIndex ModelIndex = m_pOneModel->mapToSource(Index);
|
||||
|
||||
QModelIndex ModelL = m_pModel->index(ModelIndex.row(), 0, ModelIndex.parent());
|
||||
QModelIndex ModelR = m_pModel->index(ModelIndex.row(), m_pModel->columnCount()-1, ModelIndex.parent());
|
||||
|
||||
m_pList->selectionModel()->select(QItemSelection(ModelL, ModelR), QItemSelectionModel::Deselect);
|
||||
}*/
|
||||
m_LockSellection = 0;
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnListSelectionChanged(const QItemSelection& Selected, const QItemSelection& Deselected)
|
||||
{
|
||||
if (m_LockSellection != 2)
|
||||
emit selectionChanged(Selected, Deselected);
|
||||
|
||||
if (m_LockSellection)
|
||||
return;
|
||||
m_LockSellection = 1;
|
||||
QItemSelection SelectedItems;
|
||||
foreach(const QModelIndex& Index, m_pList->selectionModel()->selectedIndexes())
|
||||
{
|
||||
QModelIndex ModelIndex = m_pOneModel->mapFromSource(Index);
|
||||
if (ModelIndex.column() != 0)
|
||||
continue;
|
||||
|
||||
QModelIndex Model = m_pOneModel->index(ModelIndex.row(), 0, ModelIndex.parent());
|
||||
|
||||
SelectedItems.append(QItemSelectionRange(Model));
|
||||
}
|
||||
m_pTree->selectionModel()->select(SelectedItems, QItemSelectionModel::ClearAndSelect);
|
||||
/*foreach(const QModelIndex& Index, Selected.indexes())
|
||||
{
|
||||
QModelIndex ModelIndex = m_pOneModel->mapFromSource(Index);
|
||||
if (ModelIndex.column() != 0)
|
||||
continue;
|
||||
m_pTree->selectionModel()->select(ModelIndex, QItemSelectionModel::Select);
|
||||
}
|
||||
foreach(const QModelIndex& Index, Deselected.indexes())
|
||||
{
|
||||
QModelIndex ModelIndex = m_pOneModel->mapFromSource(Index);
|
||||
if (ModelIndex.column() != 0)
|
||||
continue;
|
||||
m_pTree->selectionModel()->select(ModelIndex, QItemSelectionModel::Deselect);
|
||||
}*/
|
||||
m_LockSellection = 0;
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnTreeCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
if (m_LockSellection)
|
||||
return;
|
||||
m_LockSellection = 2;
|
||||
int hPos = m_pList->horizontalScrollBar()->value(); // fix horizontalScrollBar position reset on selection
|
||||
m_pList->selectionModel()->setCurrentIndex(m_pOneModel->mapToSource(current), QItemSelectionModel::SelectCurrent);
|
||||
m_pList->horizontalScrollBar()->setValue(hPos);
|
||||
m_LockSellection = 0;
|
||||
emit currentChanged(m_pOneModel->mapToSource(current), m_pOneModel->mapToSource(previous));
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnListCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
if (m_LockSellection)
|
||||
return;
|
||||
m_LockSellection = 2;
|
||||
m_pTree->selectionModel()->setCurrentIndex(m_pOneModel->mapFromSource(current), QItemSelectionModel::SelectCurrent);
|
||||
m_LockSellection = 0;
|
||||
emit currentChanged(current, previous);
|
||||
}
|
||||
|
||||
QModelIndexList CSplitTreeView::selectedRows() const
|
||||
{
|
||||
int Column = 0;
|
||||
for (int i = 0; i < m_pModel->columnCount(); i++)
|
||||
{
|
||||
if (!m_pList->isColumnHidden(i))
|
||||
{
|
||||
Column = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndexList IndexList;
|
||||
foreach(const QModelIndex& Index, m_pList->selectionModel()->selectedIndexes())
|
||||
{
|
||||
if (Index.column() == Column)
|
||||
IndexList.append(Index);
|
||||
}
|
||||
return IndexList;
|
||||
}
|
||||
|
||||
void CSplitTreeView::SetTree(bool bSet)
|
||||
{
|
||||
m_bTreeEnabled = bSet;
|
||||
emit TreeEnabled(m_bTreeEnabled);
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnTreeCustomSortByColumn(int column)
|
||||
{
|
||||
Qt::SortOrder order = m_pTree->header()->sortIndicatorOrder();
|
||||
if (order == Qt::AscendingOrder)
|
||||
SetTree(!m_bTreeEnabled);
|
||||
m_pList->sortByColumn(column, order);
|
||||
m_pTree->header()->setSortIndicatorShown(true);
|
||||
}
|
||||
|
||||
void CSplitTreeView::OnListCustomSortByColumn(int column)
|
||||
{
|
||||
Qt::SortOrder order = m_pList->header()->sortIndicatorOrder();
|
||||
if (column == 0)
|
||||
SetTree(!m_bTreeEnabled);
|
||||
else if (m_bTreeEnabled)
|
||||
SetTree(false);
|
||||
m_pTree->header()->setSortIndicatorShown(false);
|
||||
}
|
||||
|
||||
static const qint32 CSplitTreeViewMagic = 'STVs';
|
||||
|
||||
QByteArray CSplitTreeView::saveState() const
|
||||
{
|
||||
int version = 1;
|
||||
QByteArray data;
|
||||
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
|
||||
stream << qint32(CSplitTreeViewMagic);
|
||||
stream << qint32(version);
|
||||
stream << m_pList->header()->saveState();
|
||||
stream << m_pSplitter->saveState();
|
||||
stream << m_bTreeEnabled;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool CSplitTreeView::restoreState(const QByteArray &state)
|
||||
{
|
||||
int version = 1;
|
||||
QByteArray sd = state;
|
||||
QDataStream stream(&sd, QIODevice::ReadOnly);
|
||||
|
||||
qint32 marker;
|
||||
stream >> marker;
|
||||
qint32 v;
|
||||
stream >> v;
|
||||
if (marker != CSplitTreeViewMagic || v > version)
|
||||
return false;
|
||||
|
||||
QByteArray header;
|
||||
stream >> header;
|
||||
m_pList->header()->restoreState(header);
|
||||
|
||||
QByteArray splitter;
|
||||
stream >> splitter;
|
||||
m_pSplitter->restoreState(splitter);
|
||||
|
||||
stream >> m_bTreeEnabled;
|
||||
emit TreeEnabled(m_bTreeEnabled);
|
||||
|
||||
m_pTree->header()->setSortIndicatorShown(m_pList->header()->sortIndicatorSection() == 0);
|
||||
|
||||
QList<int> sizes = m_pSplitter->sizes();
|
||||
for(int i=0; i < sizes.count(); i++)
|
||||
OnSplitterMoved(sizes[i], i);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
#pragma once
|
||||
#include <qwidget.h>
|
||||
|
||||
#include "TreeViewEx.h"
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT COneColumnModel : public QIdentityProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
COneColumnModel( QObject* parrent = 0) : QIdentityProxyModel(parrent) {}
|
||||
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const { return 1; }
|
||||
};
|
||||
|
||||
class MISCHELPERS_EXPORT CSplitTreeView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CSplitTreeView(QAbstractItemModel* pModel, QWidget *parent = 0);
|
||||
virtual ~CSplitTreeView();
|
||||
|
||||
QTreeView* GetView() { return m_pList; }
|
||||
QTreeView* GetTree() { return m_pTree; }
|
||||
|
||||
void SetTree(bool bSet);
|
||||
bool IsTree() const { return m_bTreeEnabled; }
|
||||
|
||||
void SetTreeWidth(int Width);
|
||||
int GetTreeWidth() const;
|
||||
|
||||
QModelIndex currentIndex() const { return m_pList->currentIndex(); }
|
||||
QModelIndexList selectedRows() const;
|
||||
|
||||
QByteArray saveState() const;
|
||||
bool restoreState(const QByteArray &state);
|
||||
|
||||
template<class T>
|
||||
void StartUpdatingWidgets(T& OldMap, T& Map)
|
||||
{
|
||||
for(typename T::iterator I = Map.begin(); I != Map.end();)
|
||||
{
|
||||
if(I.value().first == NULL)
|
||||
I = Map.erase(I);
|
||||
else
|
||||
{
|
||||
OldMap.insert(I.key(), I.value());
|
||||
I++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void EndUpdatingWidgets(T& OldMap, T& Map)
|
||||
{
|
||||
for(typename T::iterator I = OldMap.begin(); I != OldMap.end(); I++)
|
||||
{
|
||||
Map.remove(I.key());
|
||||
if(I.value().second.isValid())
|
||||
m_pList->setIndexWidget(I.value().second, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void TreeEnabled(bool bEnabled);
|
||||
|
||||
void MenuRequested(const QPoint &);
|
||||
|
||||
void clicked(const QModelIndex& Index);
|
||||
void doubleClicked(const QModelIndex& Index);
|
||||
void currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void selectionChanged(const QItemSelection& selected, const QItemSelection& seselected);
|
||||
|
||||
public slots:
|
||||
void hideColumn(int column) { m_pList->hideColumn(column); }
|
||||
void showColumn(int column) { m_pList->showColumn(column); }
|
||||
void expand(const QModelIndex &index);
|
||||
void collapse(const QModelIndex &index);
|
||||
void resizeColumnToContents(int column) { m_pList->resizeColumnToContents(column); }
|
||||
void sortByColumn(int column) { m_pList->sortByColumn(column); }
|
||||
void expandAll() { m_pTree->expandAll(); }
|
||||
void collapseAll() { m_pTree->collapseAll(); }
|
||||
void expandToDepth(int depth) { m_pTree->expandToDepth(depth); }
|
||||
|
||||
private slots:
|
||||
void OnSplitterMoved(int pos, int index);
|
||||
|
||||
void OnClickedTree(const QModelIndex& Index);
|
||||
void OnDoubleClickedTree(const QModelIndex& Index);
|
||||
|
||||
void OnExpandTree(const QModelIndex& index);
|
||||
void OnCollapseTree(const QModelIndex& index);
|
||||
|
||||
void OnTreeSelectionChanged(const QItemSelection& Selected, const QItemSelection& Deselected);
|
||||
void OnListSelectionChanged(const QItemSelection& Selected, const QItemSelection& Deselected);
|
||||
|
||||
void OnTreeCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void OnListCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
|
||||
void OnTreeCustomSortByColumn(int column);
|
||||
void OnListCustomSortByColumn(int column);
|
||||
|
||||
private:
|
||||
|
||||
QHBoxLayout* m_pMainLayout;
|
||||
|
||||
bool m_bTreeEnabled;
|
||||
QSplitter* m_pSplitter;
|
||||
QTreeView* m_pTree;
|
||||
QTreeView* m_pList;
|
||||
QAbstractItemModel* m_pModel;
|
||||
COneColumnModel* m_pOneModel;
|
||||
|
||||
int m_LockSellection;
|
||||
};
|
|
@ -0,0 +1,76 @@
|
|||
#include "stdafx.h"
|
||||
#include "TabPanel.h"
|
||||
|
||||
CTabPanel::CTabPanel(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_pMainLayout = new QVBoxLayout();
|
||||
m_pMainLayout->setMargin(0);
|
||||
this->setLayout(m_pMainLayout);
|
||||
|
||||
#ifdef USE_QEXTWIDGETS
|
||||
m_pTabs = new QTabWidgetEx();
|
||||
m_pTabs->setMultiRow(true);
|
||||
#else
|
||||
m_pTabs = new QTabWidget();
|
||||
#endif
|
||||
m_pMainLayout->addWidget(m_pTabs);
|
||||
}
|
||||
|
||||
CTabPanel::~CTabPanel()
|
||||
{
|
||||
}
|
||||
|
||||
void CTabPanel::ShowTab(int Index, bool bShow)
|
||||
{
|
||||
if (Index >= m_AllTabs.size())
|
||||
return;
|
||||
|
||||
m_AllTabs[Index].bVisible = bShow;
|
||||
|
||||
int ActiveTab = 0;
|
||||
QStringList VisibleTabs;
|
||||
|
||||
SaveTabs(ActiveTab, VisibleTabs);
|
||||
|
||||
RebuildTabs(ActiveTab, VisibleTabs);
|
||||
}
|
||||
|
||||
void CTabPanel::AddTab(QWidget* pWidget, const QString& Name)
|
||||
{
|
||||
STab Tab{Name, pWidget, true};
|
||||
m_AllTabs.append(Tab);
|
||||
m_pTabs->addTab(Tab.pWidget, Tab.Name);
|
||||
}
|
||||
|
||||
void CTabPanel::SaveTabs(int& ActiveTab, QStringList& VisibleTabs)
|
||||
{
|
||||
ActiveTab = 0;
|
||||
VisibleTabs.clear();
|
||||
for(int i=0; i < m_AllTabs.size(); i++)
|
||||
{
|
||||
STab& Tab = m_AllTabs[i];
|
||||
|
||||
VisibleTabs.append(QString::number(Tab.bVisible));
|
||||
if (m_pTabs->currentWidget() == Tab.pWidget)
|
||||
ActiveTab = i;
|
||||
}
|
||||
}
|
||||
|
||||
void CTabPanel::RebuildTabs(const int ActiveTab, const QStringList& VisibleTabs)
|
||||
{
|
||||
m_pTabs->clear();
|
||||
for(int i=0; i < m_AllTabs.size(); i++)
|
||||
{
|
||||
STab& Tab = m_AllTabs[i];
|
||||
|
||||
if (VisibleTabs.size() <= i || VisibleTabs[i].toInt() != 0)
|
||||
{
|
||||
Tab.bVisible = true;
|
||||
|
||||
m_pTabs->addTab(Tab.pWidget, Tab.Name);
|
||||
if (i == ActiveTab)
|
||||
m_pTabs->setCurrentWidget(Tab.pWidget);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
#include <qwidget.h>
|
||||
#include "Settings.h"
|
||||
|
||||
#ifdef USE_QEXTWIDGETS
|
||||
#include "../../qextwidgets/qtabwidgetex.h"
|
||||
#endif
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CTabPanel : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CTabPanel(QWidget* parent = 0);
|
||||
virtual ~CTabPanel();
|
||||
|
||||
virtual int GetTabCount() { return m_AllTabs.size(); }
|
||||
virtual QString GetTabLabel(int Index) { if (Index >= m_AllTabs.size()) return ""; return m_AllTabs[Index].Name; }
|
||||
virtual void ShowTab(int Index, bool bShow);
|
||||
virtual bool IsTabVisible(int Index) { if (Index >= m_AllTabs.size()) return ""; return m_AllTabs[Index].bVisible; }
|
||||
|
||||
protected:
|
||||
virtual void InitializeTabs() = 0;
|
||||
virtual void AddTab(QWidget* pWidget, const QString& Name);
|
||||
virtual void RebuildTabs(const int ActiveTab, const QStringList& VisibleTabs);
|
||||
virtual void SaveTabs(int& ActiveTab, QStringList& VisibleTabs);
|
||||
|
||||
QVBoxLayout* m_pMainLayout;
|
||||
|
||||
#ifdef USE_QEXTWIDGETS
|
||||
QTabWidgetEx* m_pTabs;
|
||||
#else
|
||||
QTabWidget* m_pTabs;
|
||||
#endif
|
||||
struct STab
|
||||
{
|
||||
QString Name;
|
||||
QWidget* pWidget;
|
||||
bool bVisible;
|
||||
};
|
||||
QVector<STab> m_AllTabs;
|
||||
};
|
||||
|
|
@ -0,0 +1,502 @@
|
|||
#include "stdafx.h"
|
||||
#include "TreeItemModel.h"
|
||||
|
||||
#define FIRST_COLUMN 0
|
||||
|
||||
bool CTreeItemModel::m_DarkMode = false;
|
||||
|
||||
CTreeItemModel::CTreeItemModel(QObject *parent)
|
||||
: QAbstractItemModelEx(parent)
|
||||
{
|
||||
m_bTree = true;
|
||||
m_bUseIcons = false;
|
||||
m_Root = NULL;
|
||||
}
|
||||
|
||||
CTreeItemModel::~CTreeItemModel()
|
||||
{
|
||||
delete m_Root;
|
||||
}
|
||||
|
||||
CSimpleTreeModel::CSimpleTreeModel(QObject *parent)
|
||||
: CTreeItemModel(parent)
|
||||
{
|
||||
m_Root = MkNode(QVariant());
|
||||
}
|
||||
|
||||
QList<QVariant> CSimpleTreeModel::MakePath(const QVariantMap& Cur, const QMap<QVariant, QVariantMap>& List)
|
||||
{
|
||||
QVariant ParentID = Cur["ParentID"];
|
||||
QVariantMap Parent = List.value(ParentID);
|
||||
|
||||
QList<QVariant> Path;
|
||||
if (!Parent.isEmpty())
|
||||
{
|
||||
Path = MakePath(Parent, List);
|
||||
Path.append(ParentID);
|
||||
}
|
||||
return Path;
|
||||
}
|
||||
|
||||
bool CSimpleTreeModel::TestPath(const QList<QVariant>& Path, const QVariantMap& Cur, const QMap<QVariant, QVariantMap>& List, int Index)
|
||||
{
|
||||
QVariant ParentID = Cur["ParentID"];
|
||||
QVariantMap Parent = List.value(ParentID);
|
||||
|
||||
if (!Parent.isEmpty())
|
||||
{
|
||||
if(Index >= Path.size() || Path[Path.size() - Index - 1] != ParentID)
|
||||
return false;
|
||||
|
||||
return TestPath(Path, Parent, List, Index + 1);
|
||||
}
|
||||
|
||||
return Path.size() == Index;
|
||||
}
|
||||
|
||||
void CSimpleTreeModel::Sync(const QMap<QVariant, QVariantMap>& List)
|
||||
{
|
||||
QMap<QList<QVariant>, QList<STreeNode*> > New;
|
||||
QHash<QVariant, STreeNode*> Old = m_Map;
|
||||
|
||||
foreach (const QVariantMap& Cur, List)
|
||||
{
|
||||
QVariant ID = Cur["ID"];
|
||||
|
||||
QModelIndex Index;
|
||||
|
||||
STreeNode* pNode = static_cast<STreeNode*>(Old.value(ID));
|
||||
if(!pNode || (m_bTree ? !TestPath(pNode->Path, Cur, List) : !pNode->Path.isEmpty()))
|
||||
{
|
||||
pNode = static_cast<STreeNode*>(MkNode(ID));
|
||||
pNode->Values.resize(columnCount());
|
||||
if(m_bTree)
|
||||
pNode->Path = MakePath(Cur, List);
|
||||
pNode->IsBold = Cur["IsBold"].toBool();
|
||||
pNode->Icon = Cur["Icon"];
|
||||
New[pNode->Path].append(pNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Old[ID] = NULL;
|
||||
Index = Find(m_Root, pNode);
|
||||
}
|
||||
|
||||
//if(Index.isValid()) // this is to slow, be more precise
|
||||
// emit dataChanged(createIndex(Index.row(), 0, pNode), createIndex(Index.row(), columnCount()-1, pNode));
|
||||
|
||||
int Col = 0;
|
||||
bool State = false;
|
||||
bool Changed = false;
|
||||
|
||||
QVariantMap Values = Cur["Values"].toMap();
|
||||
for(int section = FIRST_COLUMN; section < columnCount(); section++)
|
||||
{
|
||||
if (!m_Columns.contains(section))
|
||||
continue; // ignore columns which are hidden
|
||||
|
||||
QVariant Value = Values[QString::number(section)];
|
||||
|
||||
STreeNode::SValue& ColValue = pNode->Values[section];
|
||||
|
||||
if (ColValue.Raw != Value)
|
||||
{
|
||||
Changed = true;
|
||||
ColValue.Raw = Value;
|
||||
|
||||
//ColValue.Formated =
|
||||
}
|
||||
|
||||
if(State != Changed)
|
||||
{
|
||||
if(State && Index.isValid())
|
||||
emit dataChanged(createIndex(Index.row(), Col, pNode), createIndex(Index.row(), section-1, pNode));
|
||||
State = Changed;
|
||||
Col = section;
|
||||
}
|
||||
Changed = false;
|
||||
}
|
||||
if(State && Index.isValid())
|
||||
emit dataChanged(createIndex(Index.row(), Col, pNode), createIndex(Index.row(), columnCount()-1, pNode));
|
||||
|
||||
}
|
||||
|
||||
CTreeItemModel::Sync(New, Old);
|
||||
}
|
||||
|
||||
void CTreeItemModel::Sync(QMap<QList<QVariant>, QList<STreeNode*> >& New, QHash<QVariant, STreeNode*>& Old)
|
||||
{
|
||||
Purge(m_Root, QModelIndex(), Old);
|
||||
|
||||
if(!New.isEmpty())
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
|
||||
//foreach(const QString& Path, New.uniqueKeys())
|
||||
for(QMap<QList<QVariant>, QList<STreeNode*> >::const_iterator I = New.begin(); I != New.end(); I++)
|
||||
Fill(m_Root, QModelIndex(), I.key(), 0, I.value(), I.key());
|
||||
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
emit Updated();
|
||||
}
|
||||
|
||||
/*void CTreeItemModel::CountItems()
|
||||
{
|
||||
CountItems(m_Root);
|
||||
}
|
||||
|
||||
int CTreeItemModel::CountItems(STreeNode* pRoot)
|
||||
{
|
||||
if(pRoot->Children.isEmpty())
|
||||
return 1;
|
||||
|
||||
int Counter = 0;
|
||||
foreach(STreeNode* pChild, pRoot->Children)
|
||||
Counter += CountItems(pChild);
|
||||
//pRoot->AllChildren = Counter;
|
||||
return Counter;
|
||||
}*/
|
||||
|
||||
void CTreeItemModel::Purge(STreeNode* pParent, const QModelIndex &parent, QHash<QVariant, STreeNode*> &Old)
|
||||
{
|
||||
int Removed = 0;
|
||||
|
||||
int Begin = -1;
|
||||
int End = -1;
|
||||
for(int i = pParent->Children.count()-1; i >= -1; i--)
|
||||
{
|
||||
STreeNode* pNode = i >= 0 ? pNode = pParent->Children[i] : NULL;
|
||||
if(pNode)
|
||||
Purge(pNode, index(i, 0, parent), Old);
|
||||
|
||||
bool bRemove = false;
|
||||
if(pNode && (pNode->ID.isNull() || (bRemove = Old.value(pNode->ID) != NULL)) && pNode->Children.isEmpty()) // remove it
|
||||
{
|
||||
//m_Map.remove(pNode->ID, pNode);
|
||||
m_Map.remove(pNode->ID);
|
||||
if(End == -1)
|
||||
End = i;
|
||||
}
|
||||
else // keep it
|
||||
{
|
||||
if(bRemove)
|
||||
{
|
||||
ASSERT(!pNode->Children.isEmpty()); // we wanted to remove it but we have to keep it
|
||||
//m_Map.remove(pNode->ID, pNode);
|
||||
m_Map.remove(pNode->ID);
|
||||
pNode->ID = QVariant();
|
||||
pNode->Icon.clear();
|
||||
}
|
||||
|
||||
if(End != -1) // remove whats to be removed at once
|
||||
{
|
||||
Begin = i + 1;
|
||||
|
||||
beginRemoveRows(parent, Begin, End);
|
||||
//ASSERT(pParent->Children.count() > End);
|
||||
for(int j = End; j >= Begin; j--)
|
||||
{
|
||||
pNode = pParent->Children.takeAt(j);
|
||||
delete pNode;
|
||||
Removed++;
|
||||
}
|
||||
endRemoveRows();
|
||||
|
||||
End = -1;
|
||||
Begin = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Removed > 0)
|
||||
{
|
||||
pParent->Aux.clear();
|
||||
for (int i = pParent->Children.count() - 1; i >= 0; i--)
|
||||
{
|
||||
pParent->Children[i]->Row = i;
|
||||
pParent->Aux.insert(pParent->Children[i]->ID, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTreeItemModel::Fill(STreeNode* pParent, const QModelIndex &parent, const QList<QVariant>& Paths, int PathsIndex, const QList<STreeNode*>& New, const QList<QVariant>& Path)
|
||||
{
|
||||
if(Paths.size() > PathsIndex)
|
||||
{
|
||||
QVariant CurPath = Paths.at(PathsIndex);
|
||||
STreeNode* pNode;
|
||||
int i = pParent->Aux.value(CurPath, -1);
|
||||
if(i != -1)
|
||||
pNode = pParent->Children[i];
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
pNode = MkNode(QVariant());
|
||||
pNode->Parent = pParent;
|
||||
pNode->Values.resize(columnCount());
|
||||
|
||||
//int Count = pParent->Children.count();
|
||||
//beginInsertRows(parent, Count, Count);
|
||||
pParent->Aux.insert(pNode->ID, pParent->Children.size());
|
||||
pNode->Row = pParent->Children.size();
|
||||
pParent->Children.append(pNode);
|
||||
//endInsertRows();
|
||||
}
|
||||
Fill(pNode, index(i, 0, parent), Paths, PathsIndex + 1, New, Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(QList<STreeNode*>::const_iterator I = New.begin(); I != New.end(); I++)
|
||||
{
|
||||
STreeNode* pNode = *I;
|
||||
ASSERT(pNode);
|
||||
//ASSERT(!m_Map.contains(pNode->ID));
|
||||
m_Map.insert(pNode->ID, pNode);
|
||||
pNode->Parent = pParent;
|
||||
|
||||
//int Count = pParent->Children.count();
|
||||
//beginInsertRows(parent, Count, Count);
|
||||
pParent->Aux.insert(pNode->ID, pParent->Children.size());
|
||||
pNode->Row = pParent->Children.size();
|
||||
pParent->Children.append(pNode);
|
||||
//endInsertRows();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex CTreeItemModel::FindIndex(const QVariant& ID)
|
||||
{
|
||||
if(STreeNode* pNode = m_Map.value(ID))
|
||||
return Find(m_Root, pNode);
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex CTreeItemModel::Find(STreeNode* pParent, STreeNode* pNode)
|
||||
{
|
||||
// ''find''
|
||||
ASSERT(pNode->Parent->Children[pNode->Row] == pNode);
|
||||
return createIndex(pNode->Row, FIRST_COLUMN, pNode);
|
||||
/*
|
||||
int count = pParent->Children.count();
|
||||
for(int i=0; i < count; i++)
|
||||
{
|
||||
if (pParent->Children[i] == pNode)
|
||||
{
|
||||
ASSERT(i == pNode->Row);
|
||||
return createIndex(i, FIRST_COLUMN, pNode);
|
||||
}
|
||||
|
||||
QModelIndex Index = Find(pParent->Children[i], pNode);
|
||||
if(Index.isValid())
|
||||
return Index;
|
||||
}
|
||||
return QModelIndex();
|
||||
*/
|
||||
}
|
||||
|
||||
void CTreeItemModel::Clear()
|
||||
{
|
||||
QHash<QVariant, STreeNode*> Old = m_Map;
|
||||
//beginResetModel();
|
||||
Purge(m_Root, QModelIndex(), Old);
|
||||
//endResetModel();
|
||||
ASSERT(m_Map.isEmpty());
|
||||
}
|
||||
|
||||
void CTreeItemModel::RemoveIndex(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
STreeNode* pNode = static_cast<STreeNode*>(index.internalPointer());
|
||||
ASSERT(pNode);
|
||||
|
||||
QHash<QVariant, STreeNode*> Old;
|
||||
Old[pNode->ID] = pNode;
|
||||
|
||||
Purge(m_Root, QModelIndex(), Old);
|
||||
}
|
||||
|
||||
QVariant CTreeItemModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
return Data(index, role, index.column());
|
||||
}
|
||||
|
||||
bool CTreeItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if(index.column() == FIRST_COLUMN && role == Qt::CheckStateRole)
|
||||
{
|
||||
STreeNode* pNode = static_cast<STreeNode*>(index.internalPointer());
|
||||
ASSERT(pNode);
|
||||
emit CheckChanged(pNode->ID, value.toInt() != Qt::Unchecked);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant CTreeItemModel::Data(const QModelIndex &index, int role, int section) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
//if(role == Qt::SizeHintRole)
|
||||
// return QSize(64,16); // for fixing height
|
||||
|
||||
STreeNode* pNode = static_cast<STreeNode*>(index.internalPointer());
|
||||
ASSERT(pNode);
|
||||
|
||||
if (pNode->Values.size() <= section)
|
||||
return QVariant();
|
||||
|
||||
return NodeData(pNode, role, section);
|
||||
}
|
||||
|
||||
QVariant CTreeItemModel::NodeData(STreeNode* pNode, int role, int section) const
|
||||
{
|
||||
switch(role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
STreeNode::SValue& Value = pNode->Values[section];
|
||||
return Value.Formated.isValid() ? Value.Formated : Value.Raw;
|
||||
}
|
||||
case Qt::EditRole: // sort role
|
||||
{
|
||||
STreeNode::SValue& value = pNode->Values[section];
|
||||
return value.SortKey.isValid() ? value.SortKey : value.Raw;
|
||||
}
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
QString ToolTip;
|
||||
emit ToolTipCallback(pNode->ID, ToolTip);
|
||||
if(!ToolTip.isNull())
|
||||
return ToolTip;
|
||||
break;
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
{
|
||||
if (m_bUseIcons && section == FIRST_COLUMN)
|
||||
return pNode->Icon.isValid() ? pNode->Icon : GetDefaultIcon();
|
||||
break;
|
||||
}
|
||||
case Qt::FontRole:
|
||||
{
|
||||
if (section == FIRST_COLUMN && pNode->IsBold)
|
||||
{
|
||||
QFont fnt;
|
||||
fnt.setBold(true);
|
||||
return fnt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::BackgroundRole:
|
||||
{
|
||||
if(!m_DarkMode)
|
||||
return pNode->Color.isValid() ? pNode->Color : QVariant();
|
||||
break;
|
||||
}
|
||||
case Qt::ForegroundRole:
|
||||
{
|
||||
if(m_DarkMode)
|
||||
return pNode->Color.isValid() ? pNode->Color : QVariant();
|
||||
else if (pNode->IsGray)
|
||||
{
|
||||
QColor Color = Qt::darkGray;
|
||||
return QBrush(Color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::CheckStateRole:
|
||||
{
|
||||
/*if(section == eModule)
|
||||
{
|
||||
if(pNode->...)
|
||||
return Qt::Unchecked;
|
||||
else
|
||||
return Qt::Checked;
|
||||
}*/
|
||||
break;
|
||||
}
|
||||
case Qt::UserRole:
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case FIRST_COLUMN: return pNode->ID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags CTreeItemModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
if(index.column() == 0)
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
QModelIndex CTreeItemModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
|
||||
STreeNode* pParent;
|
||||
if (!parent.isValid())
|
||||
pParent = m_Root;
|
||||
else
|
||||
pParent = static_cast<STreeNode*>(parent.internalPointer());
|
||||
|
||||
if(STreeNode* pNode = pParent->Children.count() > row ? pParent->Children[row] : NULL)
|
||||
return createIndex(row, column, pNode);
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex CTreeItemModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
STreeNode* pNode = static_cast<STreeNode*>(index.internalPointer());
|
||||
ASSERT(pNode->Parent);
|
||||
STreeNode* pParent = pNode->Parent;
|
||||
if (pParent == m_Root)
|
||||
return QModelIndex();
|
||||
|
||||
int row = 0;
|
||||
if(pParent->Parent)
|
||||
row = pParent->Parent->Children.indexOf(pParent);
|
||||
return createIndex(row, 0, pParent);
|
||||
}
|
||||
|
||||
int CTreeItemModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.column() > 0)
|
||||
return 0;
|
||||
|
||||
STreeNode* pNode;
|
||||
if (!parent.isValid())
|
||||
pNode = m_Root;
|
||||
else
|
||||
pNode = static_cast<STreeNode*>(parent.internalPointer());
|
||||
return pNode->Children.count();
|
||||
}
|
||||
|
||||
int CSimpleTreeModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return m_Headers.count();
|
||||
}
|
||||
|
||||
QVariant CSimpleTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
{
|
||||
if (section < m_Headers.size())
|
||||
return m_Headers.at(section);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
#pragma once
|
||||
#include "TreeViewEx.h"
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CTreeItemModel : public QAbstractItemModelEx
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CTreeItemModel(QObject *parent = 0);
|
||||
virtual ~CTreeItemModel();
|
||||
|
||||
void SetTree(bool bTree) { m_bTree = bTree; }
|
||||
bool IsTree() const { return m_bTree; }
|
||||
void SetUseIcons(bool bUseIcons) { m_bUseIcons = bUseIcons; }
|
||||
static void SetDarkMode(bool bDark) { m_DarkMode = bDark;}
|
||||
|
||||
//void CountItems();
|
||||
QModelIndex FindIndex(const QVariant& ID);
|
||||
void RemoveIndex(const QModelIndex &index);
|
||||
|
||||
QVariant Data(const QModelIndex &index, int role, int section) const;
|
||||
|
||||
// derived functions
|
||||
virtual QVariant data(const QModelIndex &index, int role) const;
|
||||
virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QModelIndex parent(const QModelIndex &index) const;
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const = 0;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const = 0;
|
||||
|
||||
public slots:
|
||||
void Clear();
|
||||
|
||||
signals:
|
||||
void CheckChanged(const QVariant& ID, bool State);
|
||||
void ToolTipCallback(const QVariant& ID, QString& ToolTip) const;
|
||||
void Updated();
|
||||
|
||||
protected:
|
||||
struct STreeNode
|
||||
{
|
||||
STreeNode(const QVariant& Id){
|
||||
ID = Id;
|
||||
Parent = NULL;
|
||||
Row = 0;
|
||||
//AllChildren = 0;
|
||||
|
||||
IsBold = false;
|
||||
IsGray = false;
|
||||
}
|
||||
virtual ~STreeNode(){
|
||||
foreach(STreeNode* pNode, Children)
|
||||
delete pNode;
|
||||
}
|
||||
|
||||
QVariant ID;
|
||||
|
||||
STreeNode* Parent;
|
||||
int Row;
|
||||
QList<QVariant> Path;
|
||||
QList<STreeNode*> Children;
|
||||
//int AllChildren;
|
||||
QMap<QVariant, int> Aux;
|
||||
|
||||
QVariant Icon;
|
||||
bool IsBold;
|
||||
bool IsGray;
|
||||
QColor Color;
|
||||
struct SValue
|
||||
{
|
||||
QVariant Raw;
|
||||
QVariant SortKey;
|
||||
QVariant Formated;
|
||||
};
|
||||
QVector<SValue> Values;
|
||||
};
|
||||
|
||||
virtual QVariant NodeData(STreeNode* pNode, int role, int section) const;
|
||||
|
||||
virtual STreeNode* MkNode(const QVariant& Id) = 0; // { return new STreeNode(Id); }
|
||||
|
||||
void Sync(QMap<QList<QVariant>, QList<STreeNode*> >& New, QHash<QVariant, STreeNode*>& Old);
|
||||
void Purge(STreeNode* pParent, const QModelIndex &parent, QHash<QVariant, STreeNode*>& Old);
|
||||
void Fill(STreeNode* pParent, const QModelIndex &parent, const QList<QVariant>& Paths, int PathsIndex, const QList<STreeNode*>& New, const QList<QVariant>& Path);
|
||||
QModelIndex Find(STreeNode* pParent, STreeNode* pNode);
|
||||
//int CountItems(STreeNode* pRoot);
|
||||
|
||||
virtual QVariant GetDefaultIcon() const { return QVariant(); }
|
||||
|
||||
STreeNode* m_Root;
|
||||
QHash<QVariant, STreeNode*> m_Map;
|
||||
bool m_bTree;
|
||||
bool m_bUseIcons;
|
||||
|
||||
static bool m_DarkMode;
|
||||
};
|
||||
|
||||
class MISCHELPERS_EXPORT CSimpleTreeModel : public CTreeItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CSimpleTreeModel(QObject *parent = 0);
|
||||
|
||||
void Sync(const QMap<QVariant, QVariantMap>& List);
|
||||
|
||||
void setHeaderLabels(const QStringList& Columns) { m_Headers = Columns; }
|
||||
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
||||
protected:
|
||||
virtual STreeNode* MkNode(const QVariant& Id) { return new STreeNode(Id); }
|
||||
|
||||
QList<QVariant> MakePath(const QVariantMap& Cur, const QMap<QVariant, QVariantMap>& List);
|
||||
bool TestPath(const QList<QVariant>& Path, const QVariantMap& Cur, const QMap<QVariant, QVariantMap>& List, int Index = 0);
|
||||
|
||||
QStringList m_Headers;
|
||||
};
|
|
@ -0,0 +1,346 @@
|
|||
#pragma once
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
__inline uint qHash( const QVariant & var )
|
||||
{
|
||||
if ( !var.isValid() || var.isNull() )
|
||||
//return -1;
|
||||
Q_ASSERT(0);
|
||||
|
||||
switch ( var.type() )
|
||||
{
|
||||
case QVariant::Int:
|
||||
return qHash( var.toInt() );
|
||||
break;
|
||||
case QVariant::UInt:
|
||||
return qHash( var.toUInt() );
|
||||
break;
|
||||
case QVariant::Bool:
|
||||
return qHash( var.toUInt() );
|
||||
break;
|
||||
case QVariant::Double:
|
||||
return qHash( var.toUInt() );
|
||||
break;
|
||||
case QVariant::LongLong:
|
||||
return qHash( var.toLongLong() );
|
||||
break;
|
||||
case QVariant::ULongLong:
|
||||
return qHash( var.toULongLong() );
|
||||
break;
|
||||
case QVariant::String:
|
||||
return qHash( var.toString() );
|
||||
break;
|
||||
case QVariant::Char:
|
||||
return qHash( var.toChar() );
|
||||
break;
|
||||
case QVariant::StringList:
|
||||
return qHash( var.toString() );
|
||||
break;
|
||||
case QVariant::ByteArray:
|
||||
return qHash( var.toByteArray() );
|
||||
break;
|
||||
case QVariant::Date:
|
||||
case QVariant::Time:
|
||||
case QVariant::DateTime:
|
||||
case QVariant::Url:
|
||||
case QVariant::Locale:
|
||||
case QVariant::RegExp:
|
||||
return qHash( var.toString() );
|
||||
break;
|
||||
case QVariant::Map:
|
||||
case QVariant::List:
|
||||
case QVariant::BitArray:
|
||||
case QVariant::Size:
|
||||
case QVariant::SizeF:
|
||||
case QVariant::Rect:
|
||||
case QVariant::LineF:
|
||||
case QVariant::Line:
|
||||
case QVariant::RectF:
|
||||
case QVariant::Point:
|
||||
case QVariant::PointF:
|
||||
// not supported yet
|
||||
break;
|
||||
case QVariant::UserType:
|
||||
case QVariant::Invalid:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
// could not generate a hash for the given variant
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT QAbstractItemModelEx : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QAbstractItemModelEx(QObject *parent = 0) : QAbstractItemModel(parent) {}
|
||||
virtual ~QAbstractItemModelEx() {}
|
||||
|
||||
bool IsColumnEnabled(int column)
|
||||
{
|
||||
return m_Columns.contains(column);
|
||||
}
|
||||
|
||||
void SetColumnEnabled(int column, bool set)
|
||||
{
|
||||
if (!set)
|
||||
m_Columns.remove(column);
|
||||
else
|
||||
m_Columns.insert(column);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
QSet<int> m_Columns;
|
||||
};
|
||||
|
||||
class MISCHELPERS_EXPORT QTreeViewEx: public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QTreeViewEx(QWidget *parent = 0) : QTreeView(parent)
|
||||
{
|
||||
setUniformRowHeights(true);
|
||||
|
||||
m_ColumnReset = 1;
|
||||
|
||||
header()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(header(), SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(OnMenuRequested(const QPoint &)));
|
||||
|
||||
m_pMenu = new QMenu(this);
|
||||
}
|
||||
|
||||
void setColumnReset(int iMode)
|
||||
{
|
||||
m_ColumnReset = iMode;
|
||||
}
|
||||
|
||||
void setColumnFixed(int column, bool fixed)
|
||||
{
|
||||
if (fixed)
|
||||
m_FixedColumns.insert(column);
|
||||
else
|
||||
m_FixedColumns.remove(column);
|
||||
}
|
||||
|
||||
bool isColumnFixed(int column) const
|
||||
{
|
||||
return m_FixedColumns.contains(column);
|
||||
}
|
||||
|
||||
QModelIndexList selectedRows() const
|
||||
{
|
||||
int Column = 0;
|
||||
QAbstractItemModel* pModel = model();
|
||||
for (int i = 0; i < pModel->columnCount(); i++)
|
||||
{
|
||||
if (!isColumnHidden(i))
|
||||
{
|
||||
Column = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndexList IndexList;
|
||||
foreach(const QModelIndex& Index, selectedIndexes())
|
||||
{
|
||||
if (Index.column() == Column)
|
||||
IndexList.append(Index);
|
||||
}
|
||||
return IndexList;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void StartUpdatingWidgets(T& OldMap, T& Map)
|
||||
{
|
||||
for(typename T::iterator I = Map.begin(); I != Map.end();)
|
||||
{
|
||||
if(I.value().first == NULL)
|
||||
I = Map.erase(I);
|
||||
else
|
||||
{
|
||||
OldMap.insert(I.key(), I.value());
|
||||
I++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void EndUpdatingWidgets(T& OldMap, T& Map)
|
||||
{
|
||||
for(typename T::iterator I = OldMap.begin(); I != OldMap.end(); I++)
|
||||
{
|
||||
Map.remove(I.key());
|
||||
if(I.value().second.isValid())
|
||||
setIndexWidget(I.value().second, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool restoreState(const QByteArray &state)
|
||||
{
|
||||
bool bRet = header()->restoreState(state);
|
||||
|
||||
SyncColumnsWithModel();
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
QByteArray saveState() const
|
||||
{
|
||||
return header()->saveState();
|
||||
}
|
||||
|
||||
QAbstractItemModelEx* modelEx() const
|
||||
{
|
||||
QAbstractItemModelEx* pModel = qobject_cast<QAbstractItemModelEx*>(model());
|
||||
if (!pModel)
|
||||
{
|
||||
QSortFilterProxyModel* pProxyModel = qobject_cast<QSortFilterProxyModel*>(model());
|
||||
if(pProxyModel)
|
||||
pModel = qobject_cast<QAbstractItemModelEx*>(pProxyModel->sourceModel());
|
||||
}
|
||||
return pModel;
|
||||
}
|
||||
|
||||
void SetColumnHidden(int column, bool hide, bool fixed = false)
|
||||
{
|
||||
if (!fixed && isColumnFixed(column))
|
||||
return; // can not change fixed columns
|
||||
|
||||
setColumnHidden(column, hide);
|
||||
|
||||
if(QAbstractItemModelEx* pModel = modelEx())
|
||||
pModel->SetColumnEnabled(column, !hide);
|
||||
|
||||
if (fixed)
|
||||
setColumnFixed(column, true);
|
||||
|
||||
emit ColumnChanged(column, !hide);
|
||||
}
|
||||
|
||||
signals:
|
||||
void ColumnChanged(int column, bool visible);
|
||||
void ResetColumns();
|
||||
|
||||
public slots:
|
||||
void SyncColumnsWithModel()
|
||||
{
|
||||
if(QAbstractItemModelEx* pModel = modelEx())
|
||||
{
|
||||
for (int i = 0; i < pModel->columnCount(); i++)
|
||||
pModel->SetColumnEnabled(i, !isColumnHidden(i));
|
||||
}
|
||||
}
|
||||
|
||||
void OnResetColumns()
|
||||
{
|
||||
QAbstractItemModel* pModel = model();
|
||||
for (int i = 0; i < pModel->columnCount(); i++)
|
||||
SetColumnHidden(i, false);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void OnMenuRequested(const QPoint &point)
|
||||
{
|
||||
QAbstractItemModel* pModel = model();
|
||||
|
||||
if(m_Columns.isEmpty())
|
||||
{
|
||||
for(int i=0; i < pModel->columnCount(); i++)
|
||||
{
|
||||
QString Label = pModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
|
||||
if(Label.isEmpty() || m_FixedColumns.contains(i))
|
||||
continue;
|
||||
QAction* pAction = new QAction(Label, m_pMenu);
|
||||
pAction->setCheckable(true);
|
||||
pAction->setChecked(!isColumnHidden(i));
|
||||
connect(pAction, SIGNAL(triggered()), this, SLOT(OnMenu()));
|
||||
m_pMenu->addAction(pAction);
|
||||
m_Columns[pAction] = i;
|
||||
}
|
||||
|
||||
if (m_ColumnReset)
|
||||
{
|
||||
m_pMenu->addSeparator();
|
||||
QAction* pAction = m_pMenu->addAction(tr("Reset columns"));
|
||||
if(m_ColumnReset == 1)
|
||||
connect(pAction, SIGNAL(triggered()), this, SLOT(OnResetColumns()));
|
||||
else
|
||||
connect(pAction, SIGNAL(triggered()), this, SIGNAL(ResetColumns()));
|
||||
}
|
||||
}
|
||||
|
||||
for(QMap<QAction*, int>::iterator I = m_Columns.begin(); I != m_Columns.end(); I++)
|
||||
I.key()->setChecked(!isColumnHidden(I.value()));
|
||||
|
||||
m_pMenu->popup(QCursor::pos());
|
||||
}
|
||||
|
||||
void OnMenu()
|
||||
{
|
||||
QAction* pAction = (QAction*)sender();
|
||||
int Column = m_Columns.value(pAction, -1);
|
||||
SetColumnHidden(Column, !pAction->isChecked());
|
||||
}
|
||||
|
||||
protected:
|
||||
QMenu* m_pMenu;
|
||||
QMap<QAction*, int> m_Columns;
|
||||
QSet<int> m_FixedColumns;
|
||||
int m_ColumnReset;
|
||||
};
|
||||
|
||||
class MISCHELPERS_EXPORT QStyledItemDelegateMaxH : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QStyledItemDelegateMaxH(int MaxHeight, QObject *parent = 0)
|
||||
: QStyledItemDelegate(parent) {m_MaxHeight = MaxHeight;}
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
QSize size = QStyledItemDelegate::sizeHint(option, index);
|
||||
size.setHeight(m_MaxHeight);
|
||||
return size;
|
||||
}
|
||||
|
||||
int m_MaxHeight;
|
||||
};
|
||||
|
||||
class MISCHELPERS_EXPORT CStyledGridItemDelegate : public QStyledItemDelegateMaxH
|
||||
{
|
||||
public:
|
||||
explicit CStyledGridItemDelegate(int MaxHeight, QObject * parent = 0) : CStyledGridItemDelegate(MaxHeight, false, parent) { }
|
||||
explicit CStyledGridItemDelegate(int MaxHeight, QColor Color, QObject * parent = 0) : CStyledGridItemDelegate(MaxHeight, Color, false, parent) { }
|
||||
explicit CStyledGridItemDelegate(int MaxHeight, bool Tree, QObject * parent = 0) : CStyledGridItemDelegate(MaxHeight, QColor(Qt::darkGray), false, parent) { }
|
||||
explicit CStyledGridItemDelegate(int MaxHeight, QColor Color, bool Tree, QObject * parent = 0) : QStyledItemDelegateMaxH(MaxHeight, parent) {
|
||||
m_Color = Color;
|
||||
m_Tree = Tree;
|
||||
m_Grid = true;
|
||||
}
|
||||
|
||||
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
|
||||
{
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
|
||||
if (m_Grid)
|
||||
{
|
||||
painter->save();
|
||||
painter->setPen(m_Color);
|
||||
//painter->drawRect(option.rect);
|
||||
//painter->drawLine(option.rect.left(), option.rect.top(), option.rect.right(), option.rect.top());
|
||||
painter->drawLine(option.rect.right(), option.rect.top(), option.rect.right(), option.rect.bottom());
|
||||
painter->drawLine(option.rect.left() + (m_Tree && index.column() == 0 ? 24 : 0), option.rect.bottom(), option.rect.right(), option.rect.bottom());
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
|
||||
bool m_Grid;
|
||||
bool m_Tree;
|
||||
QColor m_Color;
|
||||
};
|
|
@ -0,0 +1,150 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT QTreeWidgetEx: public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QTreeWidgetEx(QWidget *parent = 0) : QTreeWidget(parent)
|
||||
{
|
||||
setUniformRowHeights(true);
|
||||
|
||||
m_AutoFitMax = 0;
|
||||
m_ColumnReset = 1;
|
||||
|
||||
header()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(header(), SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(OnMenuRequested(const QPoint &)));
|
||||
|
||||
m_pMenu = new QMenu(this);
|
||||
|
||||
// Important: if something is shown/hidden we need a new size
|
||||
connect(this->model(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(OnExpandCollapsed()));
|
||||
connect(this->model(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(OnExpandCollapsed()));
|
||||
//connect(this->header(), SIGNAL(geometriesChanged()), this, SLOT(OnExpandCollapsed())); // fixme
|
||||
connect(this, SIGNAL(expanded(const QModelIndex &)), this, SLOT(OnExpandCollapsed()));
|
||||
connect(this, SIGNAL(collapsed(const QModelIndex &)), this, SLOT(OnExpandCollapsed()));
|
||||
}
|
||||
|
||||
static void AddSubItem(QTreeWidgetItem* pRoot, const QString& Key, const QString& Value)
|
||||
{
|
||||
QTreeWidgetItem* pItem = new QTreeWidgetItem(QStringList(Key));
|
||||
pItem->setText(1, Value);
|
||||
pRoot->addChild(pItem);
|
||||
}
|
||||
|
||||
// Use this function to make the widget autosize to show all items up to this value
|
||||
void setAutoFitMax(int AutoFitMax)
|
||||
{
|
||||
m_AutoFitMax = AutoFitMax;
|
||||
}
|
||||
|
||||
void setColumnReset(int iMode)
|
||||
{
|
||||
m_ColumnReset = iMode;
|
||||
}
|
||||
|
||||
QSize sizeHint() const {return m_AutoFitMax ? MySize() : QTreeWidget::sizeHint(); };
|
||||
QSize minimumSizeHint() const { return m_AutoFitMax ? MySize() : QTreeWidget::sizeHint(); };
|
||||
|
||||
signals:
|
||||
void ResetColumns();
|
||||
|
||||
public slots:
|
||||
void OnResetColumns()
|
||||
{
|
||||
for (int i = 0; i < columnCount(); i++)
|
||||
setColumnHidden(i, false);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void OnMenuRequested(const QPoint &point)
|
||||
{
|
||||
if(m_Columns.isEmpty())
|
||||
{
|
||||
QTreeWidgetItem* pHeader = headerItem();
|
||||
for(int i=0; i < columnCount(); i++)
|
||||
{
|
||||
QAction* pAction = new QAction(pHeader->text(i), m_pMenu);
|
||||
pAction->setCheckable(true);
|
||||
connect(pAction, SIGNAL(triggered()), this, SLOT(OnMenu()));
|
||||
m_pMenu->addAction(pAction);
|
||||
m_Columns[pAction] = i;
|
||||
}
|
||||
|
||||
if (m_ColumnReset)
|
||||
{
|
||||
m_pMenu->addSeparator();
|
||||
QAction* pAction = m_pMenu->addAction(tr("Reset columns"));
|
||||
if(m_ColumnReset == 1)
|
||||
connect(pAction, SIGNAL(triggered()), this, SLOT(OnResetColumns()));
|
||||
else
|
||||
connect(pAction, SIGNAL(triggered()), this, SIGNAL(ResetColumns()));
|
||||
}
|
||||
}
|
||||
|
||||
for(QMap<QAction*, int>::iterator I = m_Columns.begin(); I != m_Columns.end(); I++)
|
||||
I.key()->setChecked(!isColumnHidden(I.value()));
|
||||
|
||||
m_pMenu->popup(QCursor::pos());
|
||||
}
|
||||
|
||||
void OnMenu()
|
||||
{
|
||||
QAction* pAction = (QAction*)sender();
|
||||
int Column = m_Columns.value(pAction, -1);
|
||||
setColumnHidden(Column, !pAction->isChecked());
|
||||
QTimer::singleShot(10, this, SLOT(OnExpandCollapsed()));
|
||||
}
|
||||
|
||||
void OnExpandCollapsed()
|
||||
{
|
||||
if (m_AutoFitMax)
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
protected:
|
||||
QSize MySize() const
|
||||
{ //QSize tst(sizeHintForColumn(0) + 2 * frameWidth(), sizeHintForRow(0) + 2 * frameWidth());
|
||||
|
||||
int neededHight= 2 * frameWidth()+ this->header()->height();
|
||||
|
||||
QAbstractItemModel* m = this->model();
|
||||
|
||||
QModelIndex root = this->rootIndex();
|
||||
//if(this->rootIsDecorated())
|
||||
neededHight += recursiveHeightHint(root,m);
|
||||
|
||||
if (this->horizontalScrollBar()->isVisible())
|
||||
neededHight += this->horizontalScrollBar()->height();
|
||||
|
||||
if (neededHight > m_AutoFitMax)
|
||||
neededHight = m_AutoFitMax;
|
||||
|
||||
QSize temp = QTreeView::sizeHint();
|
||||
temp.setHeight(neededHight);
|
||||
return QSize(1,neededHight);
|
||||
}
|
||||
|
||||
// we need the size of all visible items -> isExpanded
|
||||
// the root item is usually shown as a non-Valid index -> !i.isValid()
|
||||
int recursiveHeightHint(QModelIndex i,QAbstractItemModel* m) const
|
||||
{
|
||||
int temp=sizeHintForIndex(i).height() + 1;
|
||||
if(this->isExpanded(i) || !i.isValid())
|
||||
{
|
||||
if(m->hasChildren(i))
|
||||
{
|
||||
int numRows = m->rowCount(i);
|
||||
for(int count =0;count<numRows;count++)
|
||||
temp+=recursiveHeightHint(m->index(count,0,i),m);
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
QMenu* m_pMenu;
|
||||
QMap<QAction*, int> m_Columns;
|
||||
int m_AutoFitMax;
|
||||
int m_ColumnReset;
|
||||
};
|
|
@ -0,0 +1,289 @@
|
|||
#include "stdafx.h"
|
||||
#include "Xml.h"
|
||||
|
||||
QString CXml::Serialize(const QVariant &Variant, bool bLazy)
|
||||
{
|
||||
QString String;
|
||||
QXmlStreamWriter xml(&String);
|
||||
Serialize(Variant, xml, bLazy);
|
||||
return String;
|
||||
}
|
||||
|
||||
QVariant CXml::Parse(const QString& String, bool bLazy)
|
||||
{
|
||||
QXmlStreamReader xml(String);
|
||||
return Parse(xml, bLazy);
|
||||
}
|
||||
|
||||
void CXml::Serialize(const QVariant& Variant, QFile* pFile)
|
||||
{
|
||||
QXmlStreamWriter xml(pFile);
|
||||
Serialize(Variant, xml);
|
||||
}
|
||||
|
||||
QVariant CXml::Parse(QFile* pFile)
|
||||
{
|
||||
QXmlStreamReader xml(pFile);
|
||||
return Parse(xml);
|
||||
}
|
||||
|
||||
void CXml::Write(const QVariant& Variant, const QString& FileName)
|
||||
{
|
||||
QFile File(FileName + ".tmp");
|
||||
File.open(QFile::WriteOnly);
|
||||
Serialize(Variant, &File);
|
||||
|
||||
QFile::rename(FileName, FileName + ".bak");
|
||||
File.rename(FileName);
|
||||
File.remove(FileName + ".bak");
|
||||
}
|
||||
|
||||
QVariant CXml::Read(const QString& FileName)
|
||||
{
|
||||
QFile File(FileName);
|
||||
File.open(QFile::ReadOnly);
|
||||
return Parse(&File);
|
||||
}
|
||||
|
||||
void CXml::Serialize(const QVariant& Variant, QXmlStreamWriter &xml, bool bLazy)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
xml.setAutoFormatting(true);
|
||||
#endif
|
||||
xml.writeStartDocument();
|
||||
Serialize("Variant", Variant, xml, bLazy);
|
||||
xml.writeEndDocument();
|
||||
}
|
||||
|
||||
QVariant CXml::Parse(QXmlStreamReader &xml, bool bLazy)
|
||||
{
|
||||
QVariant Variant;
|
||||
QString Temp;
|
||||
Parse(Temp, Variant, xml, bLazy);
|
||||
return Variant;
|
||||
}
|
||||
|
||||
void CXml::Serialize(const QString& Name, const QVariant& Variant, QXmlStreamWriter &xml, bool bLazy)
|
||||
{
|
||||
xml.writeStartElement(Name);
|
||||
xml.writeAttribute("Type", GetTypeStr(Variant.type()));
|
||||
switch(Variant.type())
|
||||
{
|
||||
case QVariant::Map:
|
||||
{
|
||||
QVariantMap Map = Variant.toMap();
|
||||
for(QVariantMap::iterator I = Map.begin(); I != Map.end(); ++I)
|
||||
Serialize(I.key(), I.value(), xml, bLazy);
|
||||
break;
|
||||
}
|
||||
case QVariant::Hash:
|
||||
{
|
||||
QVariantHash Hash = Variant.toHash();
|
||||
for(QVariantHash::iterator I = Hash.begin(); I != Hash.end(); ++I)
|
||||
Serialize(I.key(), I.value(), xml, bLazy);
|
||||
break;
|
||||
}
|
||||
case QVariant::List:
|
||||
{
|
||||
QVariantList List = Variant.toList();
|
||||
for(QVariantList::iterator I = List.begin(); I != List.end(); ++I)
|
||||
Serialize("Variant", *I, xml, bLazy);
|
||||
break;
|
||||
}
|
||||
case QVariant::StringList:
|
||||
{
|
||||
QStringList List = Variant.toStringList();
|
||||
for(QStringList::iterator I = List.begin(); I != List.end(); ++I)
|
||||
Serialize("Variant", *I, xml, bLazy);
|
||||
break;
|
||||
}
|
||||
case QVariant::ByteArray:
|
||||
if(!bLazy)
|
||||
{
|
||||
xml.writeCharacters (Variant.toByteArray().toBase64());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(Variant.canConvert(QVariant::String));
|
||||
xml.writeCharacters(Variant.toString().toUtf8().toPercentEncoding(" :;/|,'+()"));
|
||||
//xml.writeCharacters (Variant.toString().replace("\\","\\\\").replace("\r","\\r").replace("\n","\\n"));
|
||||
break;
|
||||
case QVariant::Invalid:
|
||||
break;
|
||||
}
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
bool CXml::Parse(QString &Name, QVariant &Variant, QXmlStreamReader &xml, bool bLazy)
|
||||
{
|
||||
bool bOpen = false;
|
||||
QVariant::Type eType = QVariant::Invalid;
|
||||
QString Text;
|
||||
while (!xml.atEnd())
|
||||
{
|
||||
xml.readNext();
|
||||
if (xml.error())
|
||||
break;
|
||||
if (xml.isEndDocument())
|
||||
continue;
|
||||
|
||||
if (xml.isStartElement())
|
||||
{
|
||||
bOpen = true;
|
||||
Name = xml.name().toString();
|
||||
eType = GetType(xml.attributes().value("Type").toString());
|
||||
QString Temp;
|
||||
QVariant Item;
|
||||
switch(eType)
|
||||
{
|
||||
case QVariant::Map:
|
||||
{
|
||||
QVariantMap Map;
|
||||
while(Parse(Temp, Item, xml, bLazy))
|
||||
Map.insert(Temp, Item);
|
||||
Variant = Map;
|
||||
return true;
|
||||
}
|
||||
case QVariant::Hash:
|
||||
{
|
||||
QVariantHash Hash;
|
||||
while(Parse(Temp, Item, xml, bLazy))
|
||||
Hash.insert(Temp, Item);
|
||||
Variant = Hash;
|
||||
return true;
|
||||
}
|
||||
case QVariant::List:
|
||||
{
|
||||
QVariantList List;
|
||||
while(Parse(Temp, Item, xml, bLazy))
|
||||
List.append(Item);
|
||||
Variant = List;
|
||||
return true;
|
||||
}
|
||||
case QVariant::StringList:
|
||||
{
|
||||
QStringList List;
|
||||
while(Parse(Temp, Item, xml, bLazy))
|
||||
List.append(Item.toString());
|
||||
Variant = List;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (xml.isCharacters())
|
||||
{
|
||||
if(bOpen)
|
||||
Text.append(xml.text().toString());
|
||||
}
|
||||
else if (xml.isEndElement())
|
||||
{
|
||||
if(bOpen)
|
||||
{
|
||||
if(eType == QVariant::ByteArray && !bLazy)
|
||||
Variant.setValue(QByteArray::fromBase64(Text.toLatin1()));
|
||||
else
|
||||
{
|
||||
/*bool bEsc = false;
|
||||
for(int i = 0; i < Text.size(); i++)
|
||||
{
|
||||
if(bEsc) // ESC sequence handling
|
||||
{
|
||||
switch(Text.at(i).unicode())
|
||||
{
|
||||
case L'\\': Text.replace(--i,2,"\\"); break;
|
||||
case L'r': Text.replace(--i,2,"\r"); break;
|
||||
case L'n': Text.replace(--i,2,"\n"); break;
|
||||
default: Text.replace(--i,2,"?"); break;
|
||||
}
|
||||
bEsc = false;
|
||||
}
|
||||
else if(Text.at(i) == L'\\')
|
||||
bEsc = true;
|
||||
}*/
|
||||
|
||||
Variant = QString::fromUtf8(QByteArray::fromPercentEncoding(Text.toLatin1()));
|
||||
if(eType) // type is optional
|
||||
{
|
||||
ASSERT(Variant.canConvert(eType));
|
||||
Variant.convert(eType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//ASSERT(0); // incomplete XML
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* SQVariants provides a lookup list of all known QVariant types for to/from string conversion
|
||||
*
|
||||
* Note: All commented out types dont have native to string converion
|
||||
* If there is a need to use them a manual conversion must be implemented in CXml
|
||||
*/
|
||||
struct SQVariants{
|
||||
SQVariants()
|
||||
{
|
||||
Map.insert("Invalid" , QVariant::Invalid);
|
||||
|
||||
Map.insert("Bool" , QVariant::Bool);
|
||||
Map.insert("Int" , QVariant::Int);
|
||||
Map.insert("UInt" , QVariant::UInt);
|
||||
Map.insert("LongLong" , QVariant::LongLong);
|
||||
Map.insert("ULongLong" , QVariant::ULongLong);
|
||||
Map.insert("Double" , QVariant::Double);
|
||||
Map.insert("Char" , QVariant::Char);
|
||||
Map.insert("Map" , QVariant::Map); // conainter type
|
||||
Map.insert("List" , QVariant::List); // conainter type
|
||||
Map.insert("String" , QVariant::String);
|
||||
Map.insert("StringList" , QVariant::StringList); // conainter type
|
||||
Map.insert("ByteArray" , QVariant::ByteArray);
|
||||
//Map.insert("BitArray" , QVariant::BitArray);
|
||||
Map.insert("Date" , QVariant::Date);
|
||||
Map.insert("Time" , QVariant::Time);
|
||||
Map.insert("DateTime" , QVariant::DateTime);
|
||||
Map.insert("Url" , QVariant::Url);
|
||||
/*Map.insert("Locale" , 18);
|
||||
Map.insert("Rect" , 19);
|
||||
Map.insert("RectF" , 20);
|
||||
Map.insert("Size" , 21);
|
||||
Map.insert("SizeF" , 22);
|
||||
Map.insert("Line" , 23);
|
||||
Map.insert("LineF" , 24);
|
||||
Map.insert("Point" , 25);
|
||||
Map.insert("PointF" , 26);
|
||||
Map.insert("RegExp" , 27);*/
|
||||
Map.insert("Hash" , QVariant::Hash); // conainter type
|
||||
|
||||
/*Map.insert("Font" , 64);
|
||||
Map.insert("Pixmap" , 65);
|
||||
Map.insert("Brush" , 66);
|
||||
Map.insert("Color" , 67);
|
||||
Map.insert("Palette" , 68);
|
||||
Map.insert("Icon" , 69);
|
||||
Map.insert("Image" , 70);
|
||||
Map.insert("Polygon" , 71);
|
||||
Map.insert("Region" , 72);
|
||||
Map.insert("Bitmap" , 73);
|
||||
Map.insert("Cursor" , 74);
|
||||
Map.insert("SizePolicy" , 75);
|
||||
Map.insert("KeySequence", 76);
|
||||
Map.insert("Pen" , 77);
|
||||
Map.insert("TextLength" , 78);
|
||||
Map.insert("TextFormat" , 79);
|
||||
Map.insert("Matrix" , 80);
|
||||
Map.insert("Transform" , 81);
|
||||
Map.insert("Matrix4x4" , 82);
|
||||
Map.insert("Vector2D" , 83);
|
||||
Map.insert("Vector3D" , 84);
|
||||
Map.insert("Vector4D" , 85);
|
||||
Map.insert("Quaternion" , 86);*/
|
||||
}
|
||||
QMap<QString,int> Map;
|
||||
} SQVariants;
|
||||
|
||||
QString CXml::GetTypeStr(int Type) {return SQVariants.Map.key(Type, "Invalid");}
|
||||
QVariant::Type CXml::GetType(QString Type) {return (QVariant::Type)SQVariants.Map.value(Type, 0);}
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "../mischelpers_global.h"
|
||||
|
||||
class MISCHELPERS_EXPORT CXml {
|
||||
public:
|
||||
static QString Serialize(const QVariant& Variant, bool bLazy = false);
|
||||
static QVariant Parse(const QString& String, bool bLazy = false);
|
||||
|
||||
static void Serialize(const QVariant& Variant, QFile* pFile);
|
||||
static QVariant Parse(QFile* pFile);
|
||||
|
||||
static void Write(const QVariant& Variant, const QString& FileName);
|
||||
static QVariant Read(const QString& FileName);
|
||||
|
||||
protected:
|
||||
static void Serialize(const QVariant& Variant, QXmlStreamWriter &xml, bool bLazy = false);
|
||||
static QVariant Parse(QXmlStreamReader &xml, bool bLazy = false);
|
||||
|
||||
static void Serialize(const QString& Name, const QVariant& Variant, QXmlStreamWriter &xml, bool bLazy = false);
|
||||
static bool Parse(QString &Name, QVariant &Variant, QXmlStreamReader &xml, bool bLazy = false);
|
||||
|
||||
static QString GetTypeStr(int Type);
|
||||
static QVariant::Type GetType(QString Type);
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "MiscHelpers.h"
|
||||
|
||||
MiscHelpers::MiscHelpers()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include "mischelpers_global.h"
|
||||
|
||||
#include ".\Common\CheckableMessageBox.h"
|
||||
#include ".\Common\ComboInputDialog.h"
|
||||
#include ".\Common\Common.h"
|
||||
#include ".\Common\DebugHelpers.h"
|
||||
#include ".\Common\ExitDialog.h"
|
||||
#include ".\Common\Finder.h"
|
||||
#include ".\Common\FlexError.h"
|
||||
#include ".\Common\FlowLayout.h"
|
||||
#include ".\Common\HistoryGraph.h"
|
||||
#include ".\Common\ItemChooser.h"
|
||||
#include ".\Common\KeyValueInputDialog.h"
|
||||
#include ".\Common\ListItemModel.h"
|
||||
#include ".\Common\MultiLineInputDialog.h"
|
||||
#include ".\Common\PanelView.h"
|
||||
#include ".\Common\ProgressDialog.h"
|
||||
#include ".\Common\Settings.h"
|
||||
#include ".\Common\SettingsWidgets.h"
|
||||
#include ".\Common\SmartGridWidget.h"
|
||||
#include ".\Common\SortFilterProxyModel.h"
|
||||
#include ".\Common\SplitTreeView.h"
|
||||
#include ".\Common\TabPanel.h"
|
||||
#include ".\Common\TreeItemModel.h"
|
||||
#include ".\Common\TreeViewEx.h"
|
||||
#include ".\Common\TreeWidgetEx.h"
|
||||
#include ".\Common\Xml.h"
|
||||
|
||||
class MISCHELPERS_EXPORT MiscHelpers
|
||||
{
|
||||
public:
|
||||
MiscHelpers();
|
||||
};
|
|
@ -0,0 +1,166 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{7AB8215A-59A4-4B8B-8090-16C87A860429}</ProjectGuid>
|
||||
<Keyword>QtVS_v302</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
|
||||
<QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
|
||||
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
|
||||
</Target>
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="Shared" />
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
|
||||
<Import Project="$(QtMsBuild)\qt_defaults.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<QtInstall>msvc2015_64</QtInstall>
|
||||
<QtModules>core;network;widgets;winextras</QtModules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<QtInstall>msvc2017_64_dbg</QtInstall>
|
||||
<QtModules>core;network;widgets;winextras</QtModules>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
|
||||
<Import Project="$(QtMsBuild)\qt.props" />
|
||||
</ImportGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<QtMoc>
|
||||
<PrependInclude>stdafx.h</PrependInclude>
|
||||
</QtMoc>
|
||||
<ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
<PreprocessorDefinitions>MISCHELPERS_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OutputFile>$(OutDir)\$(ProjectName).dll</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<QtMoc>
|
||||
<PrependInclude>stdafx.h</PrependInclude>
|
||||
</QtMoc>
|
||||
<ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<DebugInformationFormat />
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
<PreprocessorDefinitions>MISCHELPERS_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OutputFile>$(OutDir)\$(ProjectName).dll</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Common\CheckableMessageBox.cpp" />
|
||||
<ClCompile Include="Common\ComboInputDialog.cpp" />
|
||||
<ClCompile Include="Common\Common.cpp" />
|
||||
<ClCompile Include="Common\DebugHelpers.cpp" />
|
||||
<ClCompile Include="Common\Finder.cpp" />
|
||||
<ClCompile Include="Common\FlowLayout.cpp" />
|
||||
<ClCompile Include="Common\IconExtreactor.cpp" />
|
||||
<ClCompile Include="Common\ItemChooser.cpp" />
|
||||
<ClCompile Include="Common\KeyValueInputDialog.cpp" />
|
||||
<ClCompile Include="Common\ListItemModel.cpp" />
|
||||
<ClCompile Include="Common\MultiLineInputDialog.cpp" />
|
||||
<ClCompile Include="Common\PanelView.cpp" />
|
||||
<ClCompile Include="Common\Settings.cpp" />
|
||||
<ClCompile Include="Common\SettingsWidgets.cpp" />
|
||||
<ClCompile Include="Common\SmartGridWidget.cpp" />
|
||||
<ClCompile Include="Common\SplitTreeView.cpp" />
|
||||
<ClCompile Include="Common\TabPanel.cpp" />
|
||||
<ClCompile Include="Common\TreeItemModel.cpp" />
|
||||
<ClCompile Include="Common\Xml.cpp" />
|
||||
<ClCompile Include="MiscHelpers.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="Common\CheckableMessageBox.h" />
|
||||
<QtMoc Include="Common\ComboInputDialog.h" />
|
||||
<ClInclude Include="Common\Common.h" />
|
||||
<ClInclude Include="Common\DebugHelpers.h" />
|
||||
<ClInclude Include="Common\ExitDialog.h" />
|
||||
<QtMoc Include="Common\Finder.h" />
|
||||
<ClInclude Include="Common\FlexError.h" />
|
||||
<ClInclude Include="Common\FlowLayout.h" />
|
||||
<ClInclude Include="Common\HistoryGraph.h" />
|
||||
<QtMoc Include="Common\ItemChooser.h" />
|
||||
<QtMoc Include="Common\KeyValueInputDialog.h" />
|
||||
<QtMoc Include="Common\ListItemModel.h" />
|
||||
<QtMoc Include="Common\MultiLineInputDialog.h" />
|
||||
<QtMoc Include="Common\PanelView.h" />
|
||||
<QtMoc Include="Common\ProgressDialog.h" />
|
||||
<QtMoc Include="Common\Settings.h" />
|
||||
<QtMoc Include="Common\SettingsWidgets.h" />
|
||||
<QtMoc Include="Common\SmartGridWidget.h" />
|
||||
<QtMoc Include="Common\SortFilterProxyModel.h" />
|
||||
<QtMoc Include="Common\SplitTreeView.h" />
|
||||
<QtMoc Include="Common\TabPanel.h" />
|
||||
<QtMoc Include="Common\TreeItemModel.h" />
|
||||
<QtMoc Include="Common\TreeViewEx.h" />
|
||||
<QtMoc Include="Common\TreeWidgetEx.h" />
|
||||
<ClInclude Include="Common\IconExtreactor.h" />
|
||||
<ClInclude Include="Common\Xml.h" />
|
||||
<ClInclude Include="MiscHelpers.h" />
|
||||
<ClInclude Include="mischelpers_global.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||
<Import Project="$(QtMsBuild)\qt.targets" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties MocDir=".\GeneratedFiles\$(ConfigurationName)" UicDir=".\GeneratedFiles" RccDir=".\GeneratedFiles" lupdateOptions="" lupdateOnBuild="0" lreleaseOptions="" MocOptions="" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
|
@ -0,0 +1,184 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
|
||||
<Extensions>qrc;*</Extensions>
|
||||
<ParseFiles>false</ParseFiles>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
|
||||
<Extensions>qrc;*</Extensions>
|
||||
<ParseFiles>false</ParseFiles>
|
||||
</Filter>
|
||||
<Filter Include="Common">
|
||||
<UniqueIdentifier>{964acff8-ecee-4dfc-939d-e2406a533100}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="MiscHelpers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\CheckableMessageBox.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\ComboInputDialog.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\Common.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\DebugHelpers.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\Finder.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\FlowLayout.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\ItemChooser.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\KeyValueInputDialog.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\ListItemModel.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\MultiLineInputDialog.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\PanelView.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\Settings.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\SettingsWidgets.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\SmartGridWidget.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\SplitTreeView.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\TabPanel.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\TreeItemModel.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\Xml.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\IconExtreactor.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MiscHelpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\Common.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\DebugHelpers.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\ExitDialog.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\FlexError.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\FlowLayout.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\HistoryGraph.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\Xml.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\IconExtreactor.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="mischelpers_global.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="Common\CheckableMessageBox.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\ComboInputDialog.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\Finder.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\ItemChooser.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\KeyValueInputDialog.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\ListItemModel.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\MultiLineInputDialog.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\PanelView.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\ProgressDialog.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\Settings.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\SettingsWidgets.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\SmartGridWidget.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\SortFilterProxyModel.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\SplitTreeView.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\TabPanel.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\TreeItemModel.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\TreeViewEx.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Common\TreeWidgetEx.h">
|
||||
<Filter>Common</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef BUILD_STATIC
|
||||
# if defined(MISCHELPERS_LIB)
|
||||
# define MISCHELPERS_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define MISCHELPERS_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
#else
|
||||
# define MISCHELPERS_EXPORT
|
||||
#endif
|
|
@ -0,0 +1 @@
|
|||
#include "stdafx.h"
|
|
@ -0,0 +1,135 @@
|
|||
#pragma once
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
|
||||
|
||||
// std includes
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Qt includes
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVector>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QFile>
|
||||
#include <qglobal.h>
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
#include <QTimerEvent>
|
||||
#include <QThread>
|
||||
#include <QProcess>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QTextStream>
|
||||
#include <QFileInfo>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
#include <QUdpSocket>
|
||||
#include <QBuffer>
|
||||
#include <QDir>
|
||||
#include <QTemporaryFile>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QReadWriteLock>
|
||||
#include <QWaitCondition>
|
||||
#include <QBitArray>
|
||||
#include <QPointer>
|
||||
#include <QSharedPointer>
|
||||
#include <QFutureWatcher>
|
||||
#include <QHostInfo>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QWidget>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QSplitter>
|
||||
#include <QTabWidget>
|
||||
#include <QTextEdit>
|
||||
#include <QLabel>
|
||||
#include <QMenuBar>
|
||||
#include <QStatusBar>
|
||||
#include <QCloseEvent>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QHeaderView>
|
||||
#include <QToolBar>
|
||||
#include <QScrollBar>
|
||||
#include <QStyleFactory>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStackedLayout>
|
||||
#include <QTreeWidget>
|
||||
#include <QFormLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QTextEdit>
|
||||
#include <QWidgetAction>
|
||||
#include <QCheckBox>
|
||||
#include <QScrollArea>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QStandardItemModel>
|
||||
#include <QPainter>
|
||||
#include <QGroupBox>
|
||||
#include <QSpinBox>
|
||||
#include <QComboBox>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QPushButton>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileDialog>
|
||||
#include <QProgressBar>
|
||||
#include <QInputDialog>
|
||||
#include <QToolTip>
|
||||
#include <QColorDialog>
|
||||
#include <QToolButton>
|
||||
#include <QScreen>
|
||||
#include <QIdentityProxyModel>
|
||||
#include <QRandomGenerator>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
// other includes
|
||||
|
||||
#define _T(x) L ## x
|
||||
|
||||
#define STR2(X) #X
|
||||
#define STR(X) STR2(X)
|
||||
|
||||
#define ARRSIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
#ifndef Max
|
||||
#define Max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef Min
|
||||
#define Min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define SAFE_MODE
|
||||
#endif
|
||||
|
||||
#include "Common/DebugHelpers.h"
|
||||
|
||||
//#define USE_QEXTWIDGETS
|
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
|
@ -0,0 +1,214 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{1433EC85-BDA4-402E-BEC1-48611206A64A}</ProjectGuid>
|
||||
<Keyword>QtVS_v302</Keyword>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
|
||||
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
|
||||
</Target>
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="Shared" />
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
|
||||
<Import Project="$(QtMsBuild)\qt_defaults.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<QtInstall>msvc2015_64</QtInstall>
|
||||
<QtModules>core</QtModules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="QtSettings">
|
||||
<QtInstall>msvc2015_64</QtInstall>
|
||||
<QtModules>core</QtModules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<QtInstall>msvc2015_64</QtInstall>
|
||||
<QtModules>core</QtModules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="QtSettings">
|
||||
<QtInstall>msvc2015_64</QtInstall>
|
||||
<QtModules>core</QtModules>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
|
||||
<Import Project="$(QtMsBuild)\qt.props" />
|
||||
</ImportGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<QtMoc>
|
||||
<PrependInclude>stdafx.h</PrependInclude>
|
||||
</QtMoc>
|
||||
<ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
<PreprocessorDefinitions>QSBIEAPI_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OutputFile>$(OutDir)\$(ProjectName).dll</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<QtMoc>
|
||||
<PrependInclude>stdafx.h</PrependInclude>
|
||||
</QtMoc>
|
||||
<ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
<PreprocessorDefinitions>QSBIEAPI_LIB;UNICODE;_UNICODE;WIN32;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OutputFile>$(OutDir)\$(ProjectName).dll</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalOptions> /SUBSYSTEM:WINDOWS</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<QtMoc>
|
||||
<PrependInclude>stdafx.h</PrependInclude>
|
||||
</QtMoc>
|
||||
<ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<DebugInformationFormat />
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
<PreprocessorDefinitions>QSBIEAPI_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OutputFile>$(OutDir)\$(ProjectName).dll</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<QtMoc>
|
||||
<PrependInclude>stdafx.h</PrependInclude>
|
||||
</QtMoc>
|
||||
<ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<DebugInformationFormat>
|
||||
</DebugInformationFormat>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
<PreprocessorDefinitions>QSBIEAPI_LIB;UNICODE;_UNICODE;WIN32;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OutputFile>$(OutDir)\$(ProjectName).dll</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalOptions> /SUBSYSTEM:WINDOWS</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Sandboxie\BoxedProcess.cpp" />
|
||||
<ClCompile Include="Sandboxie\SandBox.cpp" />
|
||||
<ClCompile Include="Sandboxie\IniSection.cpp" />
|
||||
<ClCompile Include="SbieAPI.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="SbieAPI.h" />
|
||||
<ClInclude Include="qsbieapi_global.h" />
|
||||
<QtMoc Include="Sandboxie\BoxedProcess.h" />
|
||||
<QtMoc Include="Sandboxie\SandBox.h" />
|
||||
<QtMoc Include="Sandboxie\IniSection.h" />
|
||||
<ClInclude Include="SbieError.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||
<Import Project="$(QtMsBuild)\qt.targets" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties MocDir=".\GeneratedFiles\$(ConfigurationName)" UicDir=".\GeneratedFiles" RccDir=".\GeneratedFiles" lupdateOptions="" lupdateOnBuild="0" lreleaseOptions="" MocOptions="" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
|
||||
<Extensions>qrc;*</Extensions>
|
||||
<ParseFiles>false</ParseFiles>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
|
||||
<Extensions>qrc;*</Extensions>
|
||||
<ParseFiles>false</ParseFiles>
|
||||
</Filter>
|
||||
<Filter Include="SbieAPI">
|
||||
<UniqueIdentifier>{1cc5894c-f677-4167-9b99-bdc19b3ecd9d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Sandboxie">
|
||||
<UniqueIdentifier>{a34e523b-19e3-4951-b7f2-d0bcd66886d6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SbieAPI.cpp">
|
||||
<Filter>SbieAPI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Sandboxie\BoxedProcess.cpp">
|
||||
<Filter>Sandboxie</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Sandboxie\SandBox.cpp">
|
||||
<Filter>Sandboxie</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Sandboxie\IniSection.cpp">
|
||||
<Filter>Sandboxie</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SbieError.h">
|
||||
<Filter>SbieAPI</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="qsbieapi_global.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="Sandboxie\BoxedProcess.h">
|
||||
<Filter>Sandboxie</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Sandboxie\SandBox.h">
|
||||
<Filter>Sandboxie</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="SbieAPI.h">
|
||||
<Filter>SbieAPI</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Sandboxie\IniSection.h">
|
||||
<Filter>Sandboxie</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2020, David Xanatos
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "BoxedProcess.h"
|
||||
#include "SandBox.h"
|
||||
#include "../SbieAPI.h"
|
||||
|
||||
#include <ntstatus.h>
|
||||
#define WIN32_NO_STATUS
|
||||
typedef long NTSTATUS;
|
||||
|
||||
#include <windows.h>
|
||||
#include "..\..\Sandboxie\common\win32_ntddk.h"
|
||||
#include <psapi.h> // For access to GetModuleFileNameEx
|
||||
|
||||
//struct SBoxedProcess
|
||||
//{
|
||||
//};
|
||||
|
||||
CBoxedProcess::CBoxedProcess(quint64 ProcessId, class CSandBox* pBox)
|
||||
{
|
||||
m_pBox = pBox;
|
||||
|
||||
//m = new SBoxedProcess;
|
||||
|
||||
m_ProcessId = ProcessId;
|
||||
|
||||
m_ParendPID = 0;
|
||||
m_SessionId = 0;
|
||||
|
||||
m_bTerminated = false;
|
||||
m_bSuspended = IsSuspended();
|
||||
}
|
||||
|
||||
CBoxedProcess::~CBoxedProcess()
|
||||
{
|
||||
//delete m;
|
||||
}
|
||||
|
||||
void CBoxedProcess::UpdateProcessInfo()
|
||||
{
|
||||
HANDLE ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, (DWORD)m_ProcessId);
|
||||
if (ProcessHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
PROCESS_BASIC_INFORMATION BasicInformation;
|
||||
NTSTATUS status = NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &BasicInformation, sizeof(PROCESS_BASIC_INFORMATION), NULL);
|
||||
if (NT_SUCCESS(status)) {
|
||||
m_ParendPID = (quint64)BasicInformation.InheritedFromUniqueProcessId;
|
||||
}
|
||||
|
||||
TCHAR filename[MAX_PATH];
|
||||
if (DWORD size = GetModuleFileNameEx(ProcessHandle, NULL, filename, MAX_PATH))
|
||||
m_ImagePath = QString::fromWCharArray(filename);
|
||||
|
||||
NtClose(ProcessHandle);
|
||||
}
|
||||
}
|
||||
|
||||
QString CBoxedProcess::GetStatusStr() const
|
||||
{
|
||||
if (m_bTerminated)
|
||||
return tr("Terminated");
|
||||
if (m_bSuspended)
|
||||
return tr("Suspended");
|
||||
return tr("Running");
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
NTSYSCALLAPI NTSTATUS NTAPI NtTerminateProcess(_In_opt_ HANDLE ProcessHandle, _In_ NTSTATUS ExitStatus);
|
||||
NTSYSCALLAPI NTSTATUS NTAPI NtSuspendProcess(_In_ HANDLE ProcessHandle);
|
||||
NTSYSCALLAPI NTSTATUS NTAPI NtResumeProcess(_In_ HANDLE ProcessHandle);
|
||||
}
|
||||
|
||||
#include <TlHelp32.h>
|
||||
|
||||
SB_STATUS CBoxedProcess::Terminate()
|
||||
{
|
||||
return m_pBox->Api()->Terminate(m_ProcessId);
|
||||
}
|
||||
|
||||
SB_STATUS CBoxedProcess::SetSuspend(bool bSet)
|
||||
{
|
||||
HANDLE ProcessHandle = OpenProcess(PROCESS_SUSPEND_RESUME, FALSE, (DWORD)m_ProcessId);
|
||||
if (ProcessHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
NTSTATUS status;
|
||||
if(bSet)
|
||||
status = NtSuspendProcess(ProcessHandle);
|
||||
else
|
||||
status = NtResumeProcess(ProcessHandle);
|
||||
NtClose(ProcessHandle);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return SB_ERR(status);
|
||||
m_bSuspended = IsSuspended();
|
||||
return SB_OK;
|
||||
}
|
||||
return SB_ERR();
|
||||
}
|
||||
|
||||
bool CBoxedProcess::IsSuspended() const
|
||||
{
|
||||
bool isSuspended = true;
|
||||
|
||||
// todo: do that globaly once per sec for all boxed processes
|
||||
|
||||
// Note: If the specified process is a 64-bit process and the caller is a 32-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).
|
||||
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
if (hThreadSnap == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
THREADENTRY32 te32 = { 0 };
|
||||
te32.dwSize = sizeof(THREADENTRY32);
|
||||
if (Thread32First(hThreadSnap, &te32))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (te32.th32OwnerProcessID != m_ProcessId)
|
||||
continue;
|
||||
|
||||
HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID);
|
||||
|
||||
ULONG SuspendCount = 0;
|
||||
NTSTATUS status = NtQueryInformationThread(hThread, (THREADINFOCLASS)35/*ThreadSuspendCount*/, &SuspendCount, sizeof(ULONG), NULL);
|
||||
|
||||
CloseHandle(hThread);
|
||||
|
||||
if (SuspendCount == 0)
|
||||
{
|
||||
isSuspended = false;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (Thread32Next(hThreadSnap, &te32));
|
||||
}
|
||||
|
||||
CloseHandle(hThreadSnap);
|
||||
|
||||
return isSuspended;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2020, David Xanatos
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <qobject.h>
|
||||
|
||||
|
||||
#include "../SbieError.h"
|
||||
|
||||
class CBoxedProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CBoxedProcess(quint64 ProcessId, class CSandBox* pBox);
|
||||
virtual ~CBoxedProcess();
|
||||
|
||||
virtual void UpdateProcessInfo();
|
||||
|
||||
virtual quint64 GetProcessId() const { return m_ProcessId; }
|
||||
virtual quint64 GetParendPID() const { return m_ParendPID; }
|
||||
virtual QString GetProcessName() const { return m_ImageName; }
|
||||
virtual QString GetFileName() const { return m_ImagePath; }
|
||||
virtual QDateTime GetTimeStamp() const { return m_StartTime; }
|
||||
virtual QString GetStatusStr() const;
|
||||
|
||||
virtual SB_STATUS Terminate();
|
||||
virtual bool IsTerminated() const { return m_bTerminated; }
|
||||
virtual void SetTerminated() { m_bTerminated = true; }
|
||||
|
||||
virtual SB_STATUS SetSuspend(bool bSet);
|
||||
virtual bool IsSuspended() const;
|
||||
|
||||
protected:
|
||||
friend class CSbieAPI;
|
||||
|
||||
quint64 m_ProcessId;
|
||||
quint64 m_ParendPID;
|
||||
QString m_ImageName;
|
||||
QString m_ImagePath;
|
||||
quint32 m_SessionId;
|
||||
QDateTime m_StartTime;
|
||||
bool m_bTerminated;
|
||||
bool m_bSuspended;
|
||||
|
||||
class CSandBox* m_pBox;
|
||||
|
||||
//private:
|
||||
// struct SBoxedProcess* m;
|
||||
};
|
||||
|
||||
typedef QSharedPointer<CBoxedProcess> CBoxedProcessPtr;
|
||||
typedef QWeakPointer<CBoxedProcess> CBoxedProcessRef;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue