bool History::GetAllSimilar(VMenu2 &HistoryMenu,const string& Str) { int Length=static_cast<int>(Str.size()); DWORD index=0; string strHName,strHGuid,strHFile,strHData; history_record_type HType; bool HLock; unsigned __int64 id; unsigned __int64 Time; while (HistoryCfgRef()->Enum(index++,m_TypeHistory,m_HistoryName,&id,strHName,&HType,&HLock,&Time,strHGuid,strHFile,strHData,true)) { if (!StrCmpNI(Str.data(),strHName.data(),Length)) { MenuItemEx NewItem(strHName); if(HLock) { NewItem.Flags|=LIF_CHECKED; } HistoryMenu.SetUserData(&id,sizeof(id),HistoryMenu.AddItem(NewItem)); } } if(HistoryMenu.GetItemCount() == 1 && HistoryMenu.GetItemPtr(0)->strName.size() == static_cast<size_t>(Length)) { HistoryMenu.DeleteItems(); return false; } return true; }
void EditControl::SetMenuPos(VMenu2& menu) { int MaxHeight = std::min(Global->Opt->Dialogs.CBoxMaxHeight.Get(),(long long)menu.GetItemCount())+2; int NewX2 = std::max(std::min(ScrX-2,(int)m_X2), m_X1 + 20); if((ScrY-m_Y1<MaxHeight && m_Y1>ScrY/2) || MenuUp) { MenuUp = true; menu.SetPosition(m_X1, std::max(0, m_Y1-1-MaxHeight), NewX2, m_Y1-1); } else { menu.SetPosition(m_X1, m_Y1+1, NewX2, std::min(static_cast<int>(ScrY), m_Y1+1+MaxHeight)); } }
history_return_type History::ProcessMenu(string &strStr, GUID* Guid, string *pstrFile, string *pstrData, const wchar_t *Title, VMenu2 &HistoryMenu, int Height, history_record_type &Type, Dialog *Dlg) { unsigned __int64 SelectedRecord = 0; string strSelectedRecordName,strSelectedRecordGuid,strSelectedRecordFile,strSelectedRecordData; history_record_type SelectedRecordType = HR_DEFAULT; FarListPos Pos={sizeof(FarListPos)}; int MenuExitCode=-1; history_return_type RetCode = HRT_ENTER; bool Done=false; bool SetUpMenuPos=false; if (m_TypeHistory == HISTORYTYPE_DIALOG && !HistoryCfgRef()->Count(m_TypeHistory,m_HistoryName)) return HRT_CANCEL; while (!Done) { bool IsUpdate=false; HistoryMenu.DeleteItems(); { bool bSelected=false; DWORD index=0; string strHName,strHGuid,strHFile,strHData; history_record_type HType; bool HLock; unsigned __int64 id; unsigned __int64 Time; SYSTEMTIME st; GetLocalTime(&st); int LastDay=0, LastMonth = 0, LastYear = 0; const auto GetTitle = [](history_record_type Type) -> const wchar_t* { switch (Type) { case HR_VIEWER: return MSG(MHistoryView); case HR_EDITOR: case HR_EDITOR_RO: return MSG(MHistoryEdit); case HR_EXTERNAL: case HR_EXTERNAL_WAIT: return MSG(MHistoryExt); } return L""; }; while (HistoryCfgRef()->Enum(index++,m_TypeHistory,m_HistoryName,&id,strHName,&HType,&HLock,&Time,strHGuid,strHFile,strHData,m_TypeHistory==HISTORYTYPE_DIALOG)) { string strRecord; if (m_TypeHistory == HISTORYTYPE_VIEW) strRecord = GetTitle(HType) + string(L":") + (HType == HR_EDITOR_RO ? L"-" : L" "); else if (m_TypeHistory == HISTORYTYPE_FOLDER) { GUID HGuid; if(StrToGuid(strHGuid,HGuid) && HGuid != FarGuid) { Plugin *pPlugin = Global->CtrlObject->Plugins->FindPlugin(HGuid); strRecord = (pPlugin ? pPlugin->GetTitle() : L"{" + strHGuid + L"}") + L":"; if(!strHFile.empty()) strRecord += strHFile + L":"; } } auto FTTime = UI64ToFileTime(Time); SYSTEMTIME SavedTime; Utc2Local(FTTime, SavedTime); if(LastDay != SavedTime.wDay || LastMonth != SavedTime.wMonth || LastYear != SavedTime.wYear) { LastDay = SavedTime.wDay; LastMonth = SavedTime.wMonth; LastYear = SavedTime.wYear; MenuItemEx Separator; Separator.Flags = LIF_SEPARATOR; string strTime; ConvertDate(FTTime, Separator.strName, strTime, 5, FALSE, FALSE, TRUE); HistoryMenu.AddItem(Separator); } strRecord += strHName; if (m_TypeHistory != HISTORYTYPE_DIALOG) ReplaceStrings(strRecord, L"&", L"&&"); MenuItemEx MenuItem(strRecord); MenuItem.SetCheck(HLock?1:0); if (!SetUpMenuPos && m_CurrentItem==id) { MenuItem.SetSelect(TRUE); bSelected=true; } HistoryMenu.SetUserData(&id,sizeof(id),HistoryMenu.AddItem(MenuItem)); } if (!SetUpMenuPos && !bSelected && m_TypeHistory!=HISTORYTYPE_DIALOG) { FarListPos p={sizeof(FarListPos)}; p.SelectPos = HistoryMenu.GetItemCount()-1; p.TopPos = 0; HistoryMenu.SetSelectPos(&p); } } if (m_TypeHistory == HISTORYTYPE_DIALOG) { int X1,Y1,X2,Y2; Dlg->CalcComboBoxPos(nullptr, HistoryMenu.GetItemCount(), X1, Y1, X2, Y2); HistoryMenu.SetPosition(X1, Y1, X2, Y2); } else HistoryMenu.SetPosition(-1,-1,0,0); if (SetUpMenuPos) { Pos.SelectPos=Pos.SelectPos < HistoryMenu.GetItemCount() ? Pos.SelectPos : HistoryMenu.GetItemCount()-1; Pos.TopPos=std::min(Pos.TopPos,HistoryMenu.GetItemCount()-Height); HistoryMenu.SetSelectPos(&Pos); SetUpMenuPos=false; } if(m_TypeHistory == HISTORYTYPE_DIALOG && !HistoryMenu.GetItemCount()) return HRT_CANCEL; MenuExitCode=HistoryMenu.Run([&](const Manager::Key& RawKey)->int { const auto Key=RawKey.FarKey(); if (m_TypeHistory == HISTORYTYPE_DIALOG && Key==KEY_TAB) // Tab в списке хистори диалогов - аналог Enter { HistoryMenu.Close(); return 1; } HistoryMenu.GetSelectPos(&Pos); void* Data = HistoryMenu.GetUserData(nullptr, 0,Pos.SelectPos); unsigned __int64 CurrentRecord = Data? *static_cast<unsigned __int64*>(Data) : 0; int KeyProcessed = 1; switch (Key) { case KEY_CTRLR: // обновить с удалением недоступных case KEY_RCTRLR: { if (m_TypeHistory == HISTORYTYPE_FOLDER || m_TypeHistory == HISTORYTYPE_VIEW) { bool ModifiedHistory=false; SCOPED_ACTION(auto) = HistoryCfgRef()->ScopedTransaction(); DWORD index=0; string strHName,strHGuid,strHFile,strHData; history_record_type HType; bool HLock; unsigned __int64 id; unsigned __int64 Time; while (HistoryCfgRef()->Enum(index++,m_TypeHistory,m_HistoryName,&id,strHName,&HType,&HLock,&Time,strHGuid,strHFile,strHData)) { if (HLock) // залоченные не трогаем continue; // убить запись из истории bool kill=false; GUID HGuid; if(StrToGuid(strHGuid,HGuid) && HGuid != FarGuid) { if (!Global->CtrlObject->Plugins->FindPlugin(HGuid)) kill=true; else if (!strHFile.empty() && !os::fs::exists(strHFile)) kill=true; } else if (!os::fs::exists(strHName)) kill=true; if(kill) { HistoryCfgRef()->Delete(id); ModifiedHistory=true; } } if (ModifiedHistory) // избавляемся от лишних телодвижений { IsUpdate=true; HistoryMenu.Close(Pos.SelectPos); } ResetPosition(); } break; } case KEY_CTRLSHIFTNUMENTER: case KEY_RCTRLSHIFTNUMENTER: case KEY_CTRLNUMENTER: case KEY_RCTRLNUMENTER: case KEY_SHIFTNUMENTER: case KEY_CTRLSHIFTENTER: case KEY_RCTRLSHIFTENTER: case KEY_CTRLENTER: case KEY_RCTRLENTER: case KEY_SHIFTENTER: case KEY_CTRLALTENTER: case KEY_RCTRLRALTENTER: case KEY_CTRLRALTENTER: case KEY_RCTRLALTENTER: case KEY_CTRLALTNUMENTER: case KEY_RCTRLRALTNUMENTER: case KEY_CTRLRALTNUMENTER: case KEY_RCTRLALTNUMENTER: { if (m_TypeHistory == HISTORYTYPE_DIALOG) break; HistoryMenu.Close(Pos.SelectPos); Done=true; RetCode = (Key==KEY_CTRLALTENTER||Key==KEY_RCTRLRALTENTER||Key==KEY_CTRLRALTENTER||Key==KEY_RCTRLALTENTER|| Key==KEY_CTRLALTNUMENTER||Key==KEY_RCTRLRALTNUMENTER||Key==KEY_CTRLRALTNUMENTER||Key==KEY_RCTRLALTNUMENTER)? HRT_CTRLALTENTER :((Key==KEY_CTRLSHIFTENTER||Key==KEY_RCTRLSHIFTENTER||Key==KEY_CTRLSHIFTNUMENTER||Key==KEY_RCTRLSHIFTNUMENTER)? HRT_CTRLSHIFTENTER :((Key==KEY_SHIFTENTER||Key==KEY_SHIFTNUMENTER)? HRT_SHIFTETNER :HRT_CTRLENTER)); break; } case KEY_F3: case KEY_F4: case KEY_NUMPAD5: case KEY_SHIFTNUMPAD5: { if (m_TypeHistory != HISTORYTYPE_VIEW) break; HistoryMenu.Close(Pos.SelectPos); Done=true; RetCode=(Key==KEY_F4? HRT_F4 : HRT_F3); break; } // $ 09.04.2001 SVS - Фича - копирование из истории строки в Clipboard case KEY_CTRLC: case KEY_RCTRLC: case KEY_CTRLINS: case KEY_CTRLNUMPAD0: case KEY_RCTRLINS: case KEY_RCTRLNUMPAD0: { if (CurrentRecord) { string strName; if (HistoryCfgRef()->Get(CurrentRecord, strName)) SetClipboard(strName); } break; } // Lock/Unlock case KEY_INS: case KEY_NUMPAD0: { if (CurrentRecord) { HistoryCfgRef()->FlipLock(CurrentRecord); ResetPosition(); HistoryMenu.Close(Pos.SelectPos); IsUpdate=true; SetUpMenuPos=true; } break; } case KEY_SHIFTNUMDEL: case KEY_SHIFTDEL: { if (CurrentRecord && !HistoryCfgRef()->IsLocked(CurrentRecord)) { HistoryCfgRef()->Delete(CurrentRecord); ResetPosition(); HistoryMenu.Close(Pos.SelectPos); IsUpdate=true; SetUpMenuPos=true; } break; } case KEY_NUMDEL: case KEY_DEL: { if (HistoryMenu.GetItemCount() && (!Global->Opt->Confirm.HistoryClear || (Global->Opt->Confirm.HistoryClear && !Message(MSG_WARNING,2, MSG((m_TypeHistory==HISTORYTYPE_CMD || m_TypeHistory==HISTORYTYPE_DIALOG?MHistoryTitle: (m_TypeHistory==HISTORYTYPE_FOLDER?MFolderHistoryTitle:MViewHistoryTitle))), MSG(MHistoryClear), MSG(MClear),MSG(MCancel))))) { HistoryCfgRef()->DeleteAllUnlocked(m_TypeHistory,m_HistoryName); ResetPosition(); HistoryMenu.Close(Pos.SelectPos); IsUpdate=true; } break; } default: KeyProcessed = 0; } return KeyProcessed; }); if (IsUpdate) continue; Done=true; if (MenuExitCode >= 0) { SelectedRecord = *static_cast<unsigned __int64*>(HistoryMenu.GetUserData(nullptr, 0, MenuExitCode)); if (!SelectedRecord) return HRT_CANCEL; if (!HistoryCfgRef()->Get(SelectedRecord, strSelectedRecordName, &SelectedRecordType, strSelectedRecordGuid, strSelectedRecordFile, strSelectedRecordData)) return HRT_CANCEL; #if 1 //Maximus: для сетевых ресурсов - танцы с бубном if (Global->Opt->RemoteAutoLogin && SelectedRecordType != HR_EXTERNAL && SelectedRecordType != HR_EXTERNAL_WAIT // ignore external && RetCode != HRT_CTRLENTER && ((m_TypeHistory == HISTORYTYPE_FOLDER && strSelectedRecordGuid.empty()) || m_TypeHistory == HISTORYTYPE_VIEW)) { size_t DirOffset = 0; PATH_TYPE Type = ParsePath(strSelectedRecordName, &DirOffset); string strCopy = DirOffset ? strSelectedRecordName.substr(0, DirOffset) : strSelectedRecordName.data(); if (Type == PATH_REMOTE /*|| Type == PATH_REMOTEUNC*/) { auto DE = std::make_unique<elevation::suppress>(); if (os::GetFileAttributes(strSelectedRecordName) == INVALID_FILE_ATTRIBUTES) { FarMacroValue vParams[2]={L"connect",strCopy.data()}; OpenMacroInfo info={sizeof(OpenMacroInfo),2,vParams}; void* CallResult = nullptr; //we must pass (&CallResult) to avoid memory leak Global->CtrlObject->Plugins->CallPlugin(Global->Opt->KnownIDs.Network.Id, OPEN_FROMMACRO, &info, &CallResult); //CallResult==1 on succeess? } } } //Maximus: поплясали - теперь как обычно if (SelectedRecordType != HR_EXTERNAL && SelectedRecordType != HR_EXTERNAL_WAIT && RetCode != HRT_CTRLENTER && ((m_TypeHistory == HISTORYTYPE_FOLDER && strSelectedRecordGuid.empty()) || m_TypeHistory == HISTORYTYPE_VIEW) && !os::fs::exists(strSelectedRecordName)) #else if (SelectedRecordType != HR_EXTERNAL && SelectedRecordType != HR_EXTERNAL_WAIT && RetCode != HRT_CTRLENTER && ((m_TypeHistory == HISTORYTYPE_FOLDER && strSelectedRecordGuid.empty()) || m_TypeHistory == HISTORYTYPE_VIEW) && !os::fs::exists(strSelectedRecordName)) #endif { SetLastError(ERROR_FILE_NOT_FOUND); Global->CatchError(); if (SelectedRecordType == HR_EDITOR && m_TypeHistory == HISTORYTYPE_VIEW) // Edit? тогда спросим и если надо создадим { if (!Message(MSG_WARNING|MSG_ERRORTYPE,2,Title,strSelectedRecordName.data(),MSG(MViewHistoryIsCreate),MSG(MHYes),MSG(MHNo))) break; } else { Message(MSG_WARNING|MSG_ERRORTYPE,1,Title,strSelectedRecordName.data(),MSG(MOk)); } Done=false; SetUpMenuPos=true; continue; } } } if (MenuExitCode < 0 || !SelectedRecord) return HRT_CANCEL; if (m_KeepSelectedPos) { m_CurrentItem = SelectedRecord; } strStr = strSelectedRecordName; if(Guid) { if(!StrToGuid(strSelectedRecordGuid,*Guid)) *Guid = FarGuid; } if(pstrFile) *pstrFile = strSelectedRecordFile; if(pstrData) *pstrData = strSelectedRecordData; switch(RetCode) { case HRT_CANCEL: break; case HRT_ENTER: case HRT_SHIFTETNER: case HRT_CTRLENTER: case HRT_CTRLSHIFTENTER: case HRT_CTRLALTENTER: Type = SelectedRecordType; break; case HRT_F3: Type = HR_VIEWER; RetCode = HRT_ENTER; break; case HRT_F4: Type = HR_EDITOR; if (SelectedRecordType == HR_EDITOR_RO) Type = HR_EDITOR_RO; RetCode = HRT_ENTER; break; } return RetCode; }
void EnumFiles(VMenu2& Menu, const string& Str) { if(!Str.empty()) { string strStr(Str); size_t Pos = 0; if(std::count(ALL_CONST_RANGE(strStr), L'"') & 1) // odd quotes count { Pos = strStr.rfind(L'"'); } else { for(Pos=strStr.size()-1; Pos!=static_cast<size_t>(-1); Pos--) { if(strStr[Pos]==L'"') { Pos--; while(strStr[Pos]!=L'"' && Pos!=static_cast<size_t>(-1)) { Pos--; } } else if(strStr[Pos]==L' ') { Pos++; break; } } } if(Pos==static_cast<size_t>(-1)) { Pos=0; } bool StartQuote=false; if(Pos < strStr.size() && strStr[Pos]==L'"') { Pos++; StartQuote=true; } string strStart(strStr.data(),Pos); Unquote(strStr.erase(0, Pos)); if(!strStr.empty()) { string strExp = os::env::expand_strings(strStr); os::fs::enum_file Find(strExp+L"*"); bool Separator=false; std::for_each(CONST_RANGE(Find, i) { const wchar_t* FileName=PointToName(strStr); bool NameMatch=!StrCmpNI(FileName, i.strFileName.data(), StrLength(FileName)), AltNameMatch = NameMatch? false : !StrCmpNI(FileName, i.strAlternateFileName.data(), StrLength(FileName)); if(NameMatch || AltNameMatch) { strStr.resize(FileName-strStr.data()); string strAdd (strStr + (NameMatch ? i.strFileName : i.strAlternateFileName)); if (!StartQuote) QuoteSpace(strAdd); string strTmp(strStart+strAdd); if(StartQuote) strTmp += L'"'; if(!Separator) { if(Menu.GetItemCount()) { MenuItemEx Item; Item.strName = MSG(MCompletionFilesTitle); Item.Flags=LIF_SEPARATOR; Menu.AddItem(Item); } else { Menu.SetTitle(MSG(MCompletionFilesTitle)); } Separator=true; } Menu.AddItem(strTmp); } });