| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345 | //---------------------------------------------------------------------------#define NO_WIN32_LEAN_AND_MEAN#include <vcl.h>#pragma hdrstop#include <Common.h>#include "CustomScpExplorer.h"#include <algorithm>#include <Bookmarks.h>#include <Interface.h>#include <Exceptions.h>#include <CoreMain.h>#include <FileSystems.h>#include <TextsCore.h>#include <TextsWin.h>#include <HelpWin.h>#include <VCLCommon.h>#include <Progress.h>#include <SynchronizeProgress.h>#include <DragExt.h>#include <WinApi.h>#include "NonVisual.h"#include "Glyphs.h"#include "Tools.h"#include "WinConfiguration.h"#include "TerminalManager.h"#include "EditorManager.h"#include "ProgParams.h"#include "Setup.h"#include <Consts.hpp>#include <DateUtils.hpp>#include <TB2Common.hpp>#include <DirectoryMonitor.hpp>#include <System.IOUtils.hpp>#include <System.StrUtils.hpp>//---------------------------------------------------------------------------#pragma package(smart_init)#pragma link "CustomDirView"#pragma link "CustomUnixDirView"#pragma link "IEListView"#pragma link "NortonLikeListView"#pragma link "UnixDirView"#pragma link "CustomDriveView"#pragma link "UnixDriveView"#pragma link "CustomDriveView"#pragma link "TB2Dock"#pragma link "TBXStatusBars"#pragma link "TB2Item"#pragma link "TB2Toolbar"#pragma link "ThemePageControl"#pragma link "PathLabel"#pragma resource "*.dfm"//---------------------------------------------------------------------------#define WM_COMPONENT_HIDE (WM_WINSCP_USER + 4)#define WM_PASTE_FILES (WM_WINSCP_USER + 14)static const int SessionPanelCount = 3;//---------------------------------------------------------------------------class TMutexGuard{public:  TMutexGuard(HANDLE AMutex, int Message = MUTEX_RELEASE_TIMEOUT,    int Timeout = 5000)  {    FMutex = NULL;    unsigned long WaitResult = WaitForSingleObject(AMutex, Timeout);    if (WaitResult == WAIT_TIMEOUT)    {      throw Exception(LoadStr(MUTEX_RELEASE_TIMEOUT));    }    else    {      FMutex = AMutex;    }  }  ~TMutexGuard()  {    if (FMutex != NULL)    {      ReleaseMutex(FMutex);    }  }private:  HANDLE FMutex;};//---------------------------------------------------------------------------class TWindowLock{public:  TWindowLock(TCustomScpExplorerForm * Form) :    FForm(Form)  {    FForm->LockWindow();  }  ~TWindowLock()  {    FForm->UnlockWindow();  }private:  TCustomScpExplorerForm * FForm;};//---------------------------------------------------------------------------TAutoBatch::TAutoBatch(TCustomScpExplorerForm * Form) :  FForm(Form){  FForm->BatchStart(FBatchStorage);}//---------------------------------------------------------------------------TAutoBatch::~TAutoBatch(){  FForm->BatchEnd(FBatchStorage);}//---------------------------------------------------------------------------struct TTransferOperationParam{  TTransferOperationParam();  UnicodeString TargetDirectory;  bool Temp;  bool DragDrop;  int Options;  TAutoSwitch Queue;};//---------------------------------------------------------------------------TTransferOperationParam::TTransferOperationParam(){  Temp = false;  DragDrop = false;  Options = 0;  Queue = asAuto;}//---------------------------------------------------------------------------class TTransferPresetNoteData : public TObject{public:  UnicodeString Message;};//---------------------------------------------------------------------------class TTerminalNoteData : public TObject{public:  TManagedTerminal * Terminal;};//---------------------------------------------------------------------------__fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):    FFormRestored(false),    TForm(Owner){  AddStartupSequence(L"F");  FInvalid = false;  FCurrentSide = osRemote;  FEverShown = false;  FDocks = new TList();  InitControls();  DebugAssert(NonVisualDataModule && !NonVisualDataModule->ScpExplorer);  // So that UpdateCustomCommandsToolbar called from RestoreParams works  NonVisualDataModule->ScpExplorer = this;  RestoreParams();  ConfigurationChanged();  RemoteDirView->Invalidate();  FAutoOperation = false;  FOnFileOperationFinished = NULL;  FPrimaryOperation = foNone;  FForceExecution = false;  FIgnoreNextDialogChar = 0;  FErrorList = NULL;  FSynchronizeProgressForm = NULL;  FProgressForm = NULL;  FRefreshLocalDirectory = false;  FRefreshRemoteDirectory = false;  FDDExtMapFile = NULL;  // CreateMutexW keeps failing with ERROR_NOACCESS  FDDExtMutex = CreateMutexA(NULL, false, AnsiString(DRAG_EXT_MUTEX).c_str());  DebugAssert(FDDExtMutex != NULL);  FDDTargetControl = NULL;  FDelayedDeletionTimer = NULL;  FDelayedDeletionList = new TStringList();  FDDFileList = NULL;  FPendingTempSpaceWarn = false;  FCapturedLog = NULL;  FDragDropOperation = false;  memset(&FHistoryMenu, 0, sizeof(FHistoryMenu));  FAllowTransferPresetAutoSelect = true;  FSessionChanging = false;  FCopyParamDefault = L"";  FSynchronizeController = NULL;  FPendingQueueActionItem = NULL;  FLockLevel = 0;  FLockSuspendLevel = 0;  FDisabledOnLockSuspend = false;  FAlternativeDelete = false;  FTrayIcon = new ::TTrayIcon(0);  FTrayIcon->OnClick = TrayIconClick;  FMaxQueueLength = 0;  FLastContextPopupScreenPoint = TPoint(-1, -1);  FTransferResumeList = NULL;  FDeletedFiles = NULL;  FMoveToQueue = false;  StandaloneOperation = false;  FOnFeedSynchronizeError = NULL;  FOnSynchronizeAbort = NULL;  FSynchronizeTerminal = NULL;  FNeedSession = false;  FDoNotIdleCurrentTerminal = 0;  FIncrementalSearching = 0;  FQueueFileList.reset(new TQueueFileList());  FProgressSide = osCurrent;  FCalculateSizeOperation = NULL;  FDownloadingFromClipboard = false;  FClipboardFakeMonitorsPendingReset = false;  FHiContrastTheme = NULL;  InitializeRemoteThumbnailMask();  FEditorManager = new TEditorManager();  FEditorManager->OnFileChange = ExecutedFileChanged;  FEditorManager->OnFileReload = ExecutedFileReload;  FEditorManager->OnFileEarlyClosed = ExecutedFileEarlyClosed;  FEditorManager->OnFileUploadComplete = ExecutedFileUploadComplete;  FLocalEditors = new TList();  FQueueStatus = NULL;  FQueueStatusSection = new TCriticalSection();  FQueueStatusInvalidated = false;  FQueueItemInvalidated = false;  FQueueStatusUpdating = false;  FQueueActedItem = NULL;  FQueueController = new TQueueController(QueueView3);  FQueueScrollOnDragOver = new TListViewScrollOnDragOver(QueueView3, true);  FUserActionTimer = new TTimer(this);  FUserActionTimer->Enabled = false;  FUserActionTimer->Interval = 10;  FUserActionTimer->OnTimer = UserActionTimer;  FNotes = new TStringList();  FNoteTimer = new TTimer(this);  FNoteTimer->Enabled = false;  FNoteTimer->OnTimer = NoteTimer;  FOnNoteClick = NULL;  FOle32Library = LoadLibrary(L"Ole32.dll");  FDragMoveCursor = FOle32Library != NULL ?    LoadCursor(FOle32Library, MAKEINTRESOURCE(2)) : NULL;  UseSystemSettings(this);  TTBXStringList * TransferList = dynamic_cast<TTBXStringList*>(    static_cast<TObject*>(GetComponent(fcTransferList)));  DebugAssert(TransferList != NULL);  FTransferListHoverIndex = -1;  TransferList->OnChange = TransferListChange;  TransferList->OnDrawItem = TransferListDrawItem;  SetSubmenu(dynamic_cast<TTBXCustomItem *>(static_cast<TObject *>(GetComponent(fcColorMenu))), true);  SetSubmenu(NonVisualDataModule->ColorMenuItem, true);  UseDesktopFont(SessionsPageControl);  UseDesktopFont(RemoteDirView);  UseDesktopFont(RemoteDriveView);  UseDesktopFont(QueueView3);  UseDesktopFont(QueueFileList);  UseDesktopFont(QueueLabel);  UseDesktopFont(RemoteStatusBar);  reinterpret_cast<TLabel*>(QueueSplitter)->OnDblClick = QueueSplitterDblClick;  QueueSplitter->ShowHint = true;  reinterpret_cast<TLabel*>(QueueFileListSplitter)->OnDblClick = QueueFileListSplitterDblClick;  QueueFileListSplitter->ShowHint = true;  RemotePanelSplitter->ShowHint = true;  UpdateImages();  FCustomCommandMenu = CreateTBXPopupMenu(this);  FCustomCommandLocalFileList = NULL;  FCustomCommandRemoteFileList = NULL;  FSessionColors = new TPngImageList(this);  FSessionColors->ColorDepth = cd32Bit;  AddFixedSessionImages();  SessionsPageControl->Images = FSessionColors;  // Needed for Explorer (Commander calls it implicitly on its own)  UpdateSessionsPageControlHeight();  UpdateQueueLabel();  CheckStoreTransition();  CreateHiddenWindow();  StartUpdates();  // Start loading drive data, so that they are ready once we need them for StartCreationDirectoryMonitorsOnEachDrive  // (necessary for "explorer" only, as "commander" loads it for its drive menu)  DriveInfo->NeedData();}//---------------------------------------------------------------------------__fastcall TCustomScpExplorerForm::~TCustomScpExplorerForm(){  AppLog(L"Destroying main window");  FInvalid = true;  ReleaseHiContrastTheme();  if (FClipboardTerminal != NULL)  {    ClipboardClear(); // implies ClipboardStop  }  // this has to be one of the very first things to do  StopUpdateThread();  // This is needed when shuting down Windows only. Otherwise it's already set NULL from Execute()  TTerminalManager::Instance()->ScpExplorer = NULL;  delete FCustomCommandLocalFileList;  delete FCustomCommandRemoteFileList;  delete FCustomCommandMenu;  delete FTrayIcon;  FTrayIcon = NULL;  FEditorManager->CloseInternalEditors(ForceCloseInternalEditor);  delete FEditorManager;  ForceCloseLocalEditors();  delete FLocalEditors;  HideFileFindDialog();  if (FDelayedDeletionTimer)  {    DoDelayedDeletion(NULL);    SAFE_DESTROY(FDelayedDeletionTimer);  }  SAFE_DESTROY(FDelayedDeletionList);  // sometimes we do not get DDEnd so the list is not released  SAFE_DESTROY(FDDFileList);  DebugAssert(FSynchronizeController == NULL);  CloseHandle(FDDExtMutex);  FDDExtMutex = NULL;  FreeLibrary(FOle32Library);  FOle32Library = NULL;  FDragMoveCursor = NULL;  DebugAssert(!FErrorList);  if (FEverShown)  {    // when window is never shown (like when running command-line operation),    // particularly window site is not restored correctly (BoundsRect value set    // in RestoreForm gets lost during handle allocation), so we do not want    // it to be stored    AppLog(L"Storing main window configuration");    StoreParams();  }  ManagedSession = NULL;  Queue = NULL;  DebugAssert(NonVisualDataModule && (NonVisualDataModule->ScpExplorer == this));  NonVisualDataModule->ScpExplorer = NULL;  delete FQueueScrollOnDragOver;  FQueueScrollOnDragOver = NULL;  delete FQueueController;  FQueueController = NULL;  delete FQueueStatusSection;  FQueueStatusSection = NULL;  delete FQueueStatus;  FQueueStatus = NULL;  delete FUserActionTimer;  FUserActionTimer = NULL;  delete FNoteTimer;  delete FNotes;  delete FNoteData;  SAFE_DESTROY(FDocks);  SessionsPageControl->Images = NULL;  // only after clearing Terminal (after SessionListChanged => ... => AddSessionColor is called)  SAFE_DESTROY(FSessionColors);  SAFE_DESTROY(FSessionsDragDropFilesEx);  SAFE_DESTROY(FHistoryMenu[0][0]);  SAFE_DESTROY(FHistoryMenu[0][1]);  SAFE_DESTROY(FHistoryMenu[1][0]);  SAFE_DESTROY(FHistoryMenu[1][1]);  if (FHiddenWindow != NULL)  {    DestroyWindow(FHiddenWindow);    FHiddenWindow = NULL;  }  AppLog(L"Main window destroyed");}//---------------------------------------------------------------------------void TCustomScpExplorerForm::ReleaseHiContrastTheme(){  if (FHiContrastTheme != NULL)  {    ReleaseTBXTheme(FHiContrastTheme);    FHiContrastTheme = NULL;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RefreshPanel(const UnicodeString & Session, const UnicodeString & Path){  std::unique_ptr<TSessionData> Data;  if (!Session.IsEmpty())  {    bool DefaultsOnly;    Data.reset(StoredSessions->ParseUrl(Session, NULL, DefaultsOnly));  }  TTerminalManager * Manager = TTerminalManager::Instance();  for (int Index = 0; Index < Manager->Count; Index++)  {    TTerminal * Terminal = Manager->Sessions[Index];    if (Session.IsEmpty() ||        Manager->IsActiveTerminalForSite(Terminal, Data.get()))    {      if (Path.IsEmpty())      {        Terminal->ClearCaches();      }      else      {        Terminal->DirectoryModified(Path, true);      }    }  }  // We should flag a pending refresh for the background terminals or busy foreground terminals  if (HasActiveTerminal() &&      CanCommandLineFromAnotherInstance() &&      (Session.IsEmpty() || Manager->IsActiveTerminalForSite(Terminal, Data.get())) &&      (Path.IsEmpty() || UnixIsChildPath(Path, Terminal->CurrentDirectory)))  {    Terminal->ReloadDirectory();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::WMCopyData(TMessage & Message){  PCOPYDATASTRUCT CopyData = reinterpret_cast<PCOPYDATASTRUCT>(Message.LParam);  AppLogFmt(L"Received copy data message with size %d", (int(CopyData->cbData)));  size_t MessageSize = sizeof(TCopyDataMessage);  bool Result = DebugAlwaysTrue(CopyData->cbData == MessageSize);  if (Result)  {    const TCopyDataMessage & Message = *reinterpret_cast<const TCopyDataMessage *>(CopyData->lpData);    Result = (Message.Version == TCopyDataMessage::Version1);    if (Result)    {      switch (Message.Command)      {        case TCopyDataMessage::CommandCanCommandLine:          Result = CanCommandLineFromAnotherInstance();          if (Result)          {            AppLog(L"Can process command-line from other instance");          }          else          {            AppLog(L"Cannot process command-line from other instance");          }          break;        case TCopyDataMessage::CommandCommandLine:          {            UnicodeString CommandLine(Message.CommandLine);            Result = CommandLineFromAnotherInstance(CommandLine);          }          break;        case TCopyDataMessage::RefreshPanel:          RefreshPanel(Message.Refresh.Session, Message.Refresh.Path);          break;        case TCopyDataMessage::MainWindowCheck:          Result = true;          break;        default:          Result = false;          break;      }    }  }  Message.Result = Result ? 1 : 0;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CreateHiddenWindow(){  WNDCLASS WindowClass = {0};  WindowClass.lpfnWndProc = DefWindowProc;  WindowClass.hInstance = HInstance;  WindowClass.lpszClassName = HIDDEN_WINDOW_NAME;  FHiddenWindow = NULL;  if (RegisterClass(&WindowClass))  {    FHiddenWindow = CreateWindow(HIDDEN_WINDOW_NAME, L"",      WS_POPUP, 0, 0, 0, 0, 0, 0, HInstance, NULL);  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanConsole(){  return    HasActiveTerminal() &&    (Terminal->IsCapable[fcAnyCommand] || Terminal->IsCapable[fcSecondaryShell]);}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanCommandLineFromAnotherInstance(){  bool Result = Visible && !NonVisualDataModule->Busy;  return Result;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CommandLineFromAnotherInstance(  const UnicodeString & CommandLine){  TProgramParams Params(CommandLine);  bool Result = CanCommandLineFromAnotherInstance() && DebugAlwaysTrue(Params.ParamCount > 0);  if (Result)  {    NonVisualDataModule->StartBusy();    try    {      // this action is initiated from another process,      // so it's likely that our window is not visible,      // and user won't see what is going on      Application->BringToFront();      // reload sessions as we may be asked to open a session      // just stored by another instance      StoredSessions->Reload();      UnicodeString SessionName = Params.Param[1];      std::unique_ptr<TObjectList> DataList(new TObjectList());      try      {        UnicodeString DownloadFile; // unused        int Flags = GetCommandLineParseUrlFlags(&Params);        GetLoginData(SessionName, &Params, DataList.get(), DownloadFile, true, this, Flags);      }      catch (EAbort &)      {        // Happens when opening session in PuTTY and in other situations,        // in which we do not want to fail WM_COPYDATA, as that would cause master instance        // to process the command-line on its own (or to pass it to yet another instance)      }      if (DataList->Count > 0)      {        TTerminalManager * Manager = TTerminalManager::Instance();        Manager->ActiveSession = Manager->NewSessions(DataList.get());      }    }    __finally    {      NonVisualDataModule->EndBusy();    }  }  return Result;}//---------------------------------------------------------------------------TManagedTerminal * TCustomScpExplorerForm::GetTerminal(){  TManagedTerminal * Result;  if ((FManagedSession != NULL) && !FManagedSession->LocalBrowser)  {    Result = FManagedSession;  }  else  {    Result = NULL;  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetManagedSession(TManagedTerminal * value){  if (FManagedSession != value)  {    TWindowLock Lock(this);    SessionChanging();    DoSetManagedSession(value, false);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoSetManagedSession(TManagedTerminal * value, bool Replace){  DebugAssert(!Replace || ((value != NULL) && !value->LocalBrowser));  FManagedSession = value;  {    TValueRestorer<bool> AllowTransferPresetAutoSelectRestorer(FAllowTransferPresetAutoSelect, false);    TAutoFlag SessionChangingFlag(FSessionChanging);    SessionChanged(Replace);  }  if (Terminal != NULL)  {    TransferPresetAutoSelect();  }  // Update app and tab titles, prevented above by FSessionChanging.  UpdateControls();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ReplaceTerminal(TManagedTerminal * value){  FEditorManager->ProcessFiles(FileTerminalReplaced, value);  DoSetManagedSession(value, true);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionChanging(){  if (ManagedSession != NULL)  {    UpdateSession(ManagedSession);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionChanged(bool Replaced){  if (ManagedSession != NULL)  {    UpdateSessionColor(static_cast<TColor>(ManagedSession->StateData->Color));  }  if (!TTerminalManager::Instance()->Updating)  {    SessionListChanged();  }  if (Terminal != NULL)  {    TObject * State = NULL;    if (WinConfiguration->PreservePanelState)    {      State = Terminal->RemoteExplorerState;      DirView(osRemote)->AnnounceState(State);    }    try    {      if (Replaced)      {        RemoteDirView->ReplaceTerminal(Terminal);      }      else      {        RemoteDirView->Terminal = Terminal;      }      if (Terminal->Active)      {        Terminal->RefreshDirectory();      }      if (State != NULL)      {        DirView(osRemote)->RestoreState(State);      }    }    __finally    {      DirView(osRemote)->AnnounceState(NULL);    }  }  else  {    RemoteDirView->Terminal = NULL;  }  InitStatusBar();  UpdateTransferList();  // Update panels Enable state before refreshing the labels  UpdateControls();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetQueue(TTerminalQueue * value){  if (Queue != value)  {    if (FQueue != NULL)    {      FQueue->OnListUpdate = NULL;      FQueue->OnQueueItemUpdate = NULL;    }    FQueue = value;    if (FQueue != NULL)    {      DebugAssert(FQueue->OnListUpdate == NULL);      FQueue->OnListUpdate = QueueListUpdate;      DebugAssert(FQueue->OnQueueItemUpdate == NULL);      FQueue->OnQueueItemUpdate = QueueItemUpdate;    }    QueueChanged();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3Deletion(TObject * /*Sender*/,  TListItem * Item){  if (FQueueActedItem == Item)  {    FQueueActedItem = NULL;    if ((QueueView3->PopupMenu != NULL) &&        (QueueView3->PopupMenu->PopupComponent == QueueView3))    {      // rather "trick", suggested by Jordan on jrsoftware.toolbar2000      ReleaseCapture();    }  }  if (Item->Data == FPendingQueueActionItem)  {    FPendingQueueActionItem = NULL;  }}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::IsAnythingQueued(){  return (FQueueStatus != NULL) && (FQueueStatus->ActiveAndPendingPrimaryCount > 0);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateQueueStatus(bool QueueChanging){  {    TGuard Guard(FQueueStatusSection);    FQueueStatusInvalidated = false;    if (FQueue != NULL)    {      FQueueStatus = FQueue->CreateStatus(FQueueStatus);    }  }  if ((FQueueStatus != NULL) && (FQueueStatus->Count > FMaxQueueLength))  {    FMaxQueueLength = FQueueStatus->Count;    Configuration->Usage->SetMax(L"MaxQueueLength", FMaxQueueLength);  }  {    TAutoFlag Flag(FQueueStatusUpdating);    FQueueController->UpdateQueueStatus(FQueueStatus);  }  UpdateQueueFileList();  SetQueueProgress();  UpdateQueueView();  bool IsEmpty = !IsAnythingQueued();  if (IsEmpty && (Terminal != NULL))  {    TOnceDoneOperation OnceDoneOperation =      NonVisualDataModule->CurrentQueueOnceEmptyOperation();    NonVisualDataModule->ResetQueueOnceEmptyOperation();    if ((FQueue != NULL) && !WinConfiguration->EnableQueueByDefault && !QueueChanging)    {      FQueue->Enabled = false;    }    if ((OnceDoneOperation != odoIdle) && !NonVisualDataModule->Busy)    {      Terminal->CloseOnCompletion(OnceDoneOperation, LoadStr(CLOSED_ON_QUEUE_EMPTY));    }  }}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::GetQueueProgressTitle(){  UnicodeString Result;  if (FQueueStatus != NULL)  {    if (FQueueStatus->IsOnlyOneActiveAndNoPending())    {      TFileOperationProgressType * ProgressData =        FQueueStatus->Items[FQueueStatus->DoneCount]->ProgressData;      if ((ProgressData != NULL) && ProgressData->InProgress)      {        Result = TProgressForm::ProgressStr(NULL, ProgressData);      }    }    else if (FQueueStatus->ActiveAndPendingPrimaryCount > 1)    {      Result = FMTLOAD(PROGRESS_IN_QUEUE, (FQueueStatus->ActiveAndPendingPrimaryCount));    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateQueueView(){  ComponentVisible[fcQueueView] =    !IsLocalBrowserMode() &&    ((WinConfiguration->QueueView.Show == qvShow) ||     ((WinConfiguration->QueueView.Show == qvHideWhenEmpty) &&      (FQueueStatus != NULL) && (FQueueStatus->Count > 0)));}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueChanged(){  if (FQueueStatus != NULL)  {    // UpdateFileList implementation relies on the status being recreated when session changes    delete FQueueStatus;    FQueueStatus = NULL;  }  UpdateQueueStatus(true);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueListUpdate(TTerminalQueue * Queue){  if (FQueue == Queue)  {    FQueueStatusInvalidated = true;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueItemUpdate(TTerminalQueue * Queue,  TQueueItem * Item){  if (FQueue == Queue)  {    TGuard Guard(FQueueStatusSection);    // this may be running in parallel with QueueChanged    if (FQueueStatus != NULL)    {      TQueueItemProxy * QueueItem = FQueueStatus->FindByQueueItem(Item);      if ((Item->Status == TQueueItem::qsDone) && (Terminal != NULL))      {        FRefreshLocalDirectory = (QueueItem == NULL) ||          (!QueueItem->Info->ModifiedLocal.IsEmpty());        FRefreshRemoteDirectory = (QueueItem == NULL) ||          (!QueueItem->Info->ModifiedRemote.IsEmpty());      }      if (QueueItem != NULL)      {        QueueItem->UserData = (void*)true;        FQueueItemInvalidated = true;      }    }  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::IsQueueAutoPopup(){  // during standalone editing, we have no way to see/control queue,  // so we have to always popup prompts automatically  return StandaloneOperation || GUIConfiguration->QueueAutoPopup;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RefreshQueueItems(){  if (FQueueStatus != NULL)  {    bool QueueAutoPopup = IsQueueAutoPopup();    bool NeedRefresh = FQueueController->NeedRefresh();    bool Refresh = FQueueItemInvalidated || NeedRefresh;    FQueueItemInvalidated = false;    int Limit = Refresh ? FQueueStatus->Count : FQueueStatus->DoneAndActiveCount;    bool Updated = false;    TQueueItemProxy * QueueItem;    bool WasUserAction;    for (int Index = 0; Index < Limit; Index++)    {      bool Update = false;      QueueItem = FQueueStatus->Items[Index];      WasUserAction = TQueueItem::IsUserActionStatus(QueueItem->Status);      if (!NonVisualDataModule->Busy && QueueAutoPopup && WasUserAction &&          (FPendingQueueActionItem == NULL))      {        FPendingQueueActionItem = QueueItem;        FUserActionTimer->Enabled = true;      }      if ((bool)QueueItem->UserData)      {        QueueItem->UserData = (void*)false;        QueueItem->Update();        Updated = true;        Update = true;      }      else if (FQueueController->QueueItemNeedsFrequentRefresh(QueueItem) || NeedRefresh)      {        Update = true;      }      if (Update)      {        FQueueController->RefreshQueueItem(QueueItem);      }    }    if (Updated)    {      NonVisualDataModule->UpdateNonVisibleActions();      SetQueueProgress();      UpdateQueueFileList();    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetTaskbarListProgressState(TBPFLAG Flags){  if (FTaskbarList != NULL)  {    // Could now use Application->MainFormHandle, now that we implement Application->OnGetMainFormHandle    FTaskbarList->SetProgressState(GetMainForm()->Handle, Flags);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetTaskbarListProgressValue(int Progress){  if (Progress >= 0)  {    if (FTaskbarList != NULL)    {      FTaskbarList->SetProgressValue(GetMainForm()->Handle, Progress, 100);    }  }  else  {    SetTaskbarListProgressState(TBPF_INDETERMINATE);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetTaskbarListProgressValue(TFileOperationProgressType * ProgressData){  int OverallProgress;  // FProgressForm is null when this is called from SetQueueProgress  if ((FProgressForm != NULL) && (FProgressForm->SynchronizeProgress != NULL))  {    OverallProgress = FProgressForm->SynchronizeProgress->Progress(ProgressData);  }  else if (!ProgressData->IsIndeterminate())  {    OverallProgress = ProgressData->OverallProgress();  }  else  {    OverallProgress = -1;  }  SetTaskbarListProgressValue(OverallProgress);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetQueueProgress(){  TTerminalManager::Instance()->QueueStatusUpdated();  if ((FTaskbarList != NULL) && (FProgressForm == NULL))  {    // Do not animate task bar button, when items are queued, but processing is disabled    if ((FQueueStatus != NULL) && (FQueueStatus->ActivePrimaryCount > 0))    {      if (FQueueStatus->IsOnlyOneActiveAndNoPending())      {        TFileOperationProgressType * ProgressData = NULL;        if (FQueueStatus->Items[FQueueStatus->DoneCount] != NULL)        {          ProgressData = FQueueStatus->Items[FQueueStatus->DoneCount]->ProgressData;        }        if ((ProgressData != NULL) &&            ProgressData->InProgress)        {          SetTaskbarListProgressValue(ProgressData);        }        else        {          SetTaskbarListProgressState(TBPF_NOPROGRESS);        }      }      else      {        SetTaskbarListProgressState(TBPF_INDETERMINATE);      }    }    else    {      SetTaskbarListProgressState(TBPF_NOPROGRESS);    }  }  UpdateQueueLabel();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateQueueLabel(){  UnicodeString Caption = LoadStr(QUEUE_CAPTION);  if (FQueueStatus != NULL)  {    int ActiveAndPendingPrimaryCount = FQueueStatus->ActiveAndPendingPrimaryCount;    if (ActiveAndPendingPrimaryCount > 0)    {      Caption = FORMAT("%s (%d)", (Caption, ActiveAndPendingPrimaryCount));    }  }  QueueLabel->Caption = Caption;}//---------------------------------------------------------------------------void TCustomScpExplorerForm::CheckStoreTransition(){  if (WinConfiguration->StoreTransition == stInit)  {    if (IsUWP())    {      WinConfiguration->StoreTransition = stStoreFresh;      AppLog(L"Fresh UWP/store installation");    }    else    {      WinConfiguration->StoreTransition = stStandard;      AppLog(L"Fresh standard installation");    }  }  else if ((WinConfiguration->StoreTransition == stStandard) && IsUWP())  {    WinConfiguration->StoreTransition = stStoreMigrated;    WinConfiguration->FirstRun = WinConfiguration->FirstRun + L"=>" + StandardDatestamp();    AppLog(L"Standard installation migrated to store installation");  }  if (WinConfiguration->StoreTransition == stStoreMigrated)  {    TTBXToolbar * Toolbar = new TTBXToolbar(MessageDock);    Toolbar->Parent = MessageDock;    Toolbar->FullSize = true;    Toolbar->Color = Application->HintColor;    TTBXLabelItem * LabelItem;    LabelItem = new TTBXLabelItem(Toolbar);    // Convert to explicit RGB "black" color, to make sure it is contrasting even in Dark theme    // (TTBXOfficeXPTheme.GetStandardColor would convert clWindow to "white" in dark theme)    LabelItem->FontSettings->Color = static_cast<TColor>(GetSysColor(clWindow));    LabelItem->Margin = ScaleByTextHeight(MessageDock, 2); // Is this automatically rescaled?    LabelItem->Caption = LoadStr(STORE_MIGRATION_THANKS);    Toolbar->Items->Add(LabelItem);    TTBXCustomItem * LinkItem = new TTBXItem(Toolbar);    LinkItem->FontSettings->Color = LinkColor;    LinkItem->Caption = LoadStr(STORE_MIGRATION_LEARN);    LinkItem->OnClick = StoreTransitionLinkClick;    Toolbar->Items->Add(LinkItem);    AddMenuSeparator(Toolbar->Items);    TTBXCustomItem * CloseItem = new TTBXItem(Toolbar);    CloseItem->FontSettings->Color = static_cast<TColor>(GetSysColor(clWindow));    CloseItem->Caption = LoadStr(MESSAGE_DISMISS);    CloseItem->OnClick = StoreTransitionCloseClick;    Toolbar->Items->Add(CloseItem);    GiveTBItemPriority(CloseItem);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::StoreTransitionLinkClick(TObject *){  ShowHelp(HELP_STORE_TRANSITION);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::StoreTransitionCloseClick(TObject * Sender){  TTBCustomItem * Item = DebugNotNull(dynamic_cast<TTBCustomItem *>(Sender));  TTBXToolbar * Toolbar = DebugNotNull(dynamic_cast<TTBXToolbar *>(DebugNotNull(DebugNotNull(Item->Parent)->ParentComponent)));  delete Toolbar;  WinConfiguration->StoreTransition = stStoreAcknowledged;  UpdateControls();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateTransferList(){  TTBXStringList * TransferList = dynamic_cast<TTBXStringList*>(    static_cast<TComponent*>(GetComponent(fcTransferList)));  TTBXDropDownItem * TransferDropDown = dynamic_cast<TTBXDropDownItem*>(    static_cast<TComponent*>(GetComponent(fcTransferDropDown)));  TransferList->Strings->BeginUpdate();  try  {    TransferList->Strings->Assign(GUIConfiguration->CopyParamList->NameList);    TransferList->Strings->Insert(0, StripHotkey(LoadStr(COPY_PARAM_DEFAULT)));    TransferList->ItemIndex = GUIConfiguration->CopyParamIndex + 1;    if (FTransferDropDownHint.IsEmpty())    {      FTransferDropDownHint = TransferDropDown->Hint;    }    // this way we get name for "default" settings (COPY_PARAM_DEFAULT)    UnicodeString Name = TransferList->Strings->Strings[TransferList->ItemIndex];    TransferDropDown->Text = StripHotkey(Name);    TransferDropDown->Hint = FORMAT(L"%s|%s:\n%s",      (FTransferDropDownHint, StripHotkey(Name),       GUIConfiguration->CurrentCopyParam.GetInfoStr(L"; ",         FLAGMASK(HasActiveTerminal(), Terminal->UsableCopyParamAttrs(0).General))));    // update the label, otherwise when it is updated only on the first draw    // of the list, it is drawn "bold" for some reason    FTransferListHoverIndex = TransferList->ItemIndex;    UpdateTransferLabel();  }  __finally  {    TransferList->Strings->EndUpdate();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateCustomCommandsToolbar(){  TTBXToolbar * Toolbar = dynamic_cast<TTBXToolbar *>(GetComponent(fcCustomCommandsBand));  DebugAssert(Toolbar != NULL);  NonVisualDataModule->UpdateCustomCommandsToolbar(Toolbar);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateActions(){  TForm::UpdateActions();  if (ComponentVisible[fcCustomCommandsBand])  {    UpdateCustomCommandsToolbar();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateSessionsPageControlHeight(){  SessionsPageControl->Height = SessionsPageControl->GetTabsHeight();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateRowSelect(TCustomDirView * DirView){  if (DirView->RowSelect != WinConfiguration->FullRowSelect)  {    DirView->RowSelect = WinConfiguration->FullRowSelect;    // Without this, the panel turns gray and unused part of header turns black    DirView->Perform(CM_COLORCHANGED, 0, 0);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ConfigurationChanged(){  Color = GetBtnFaceColor();  DebugAssert(Configuration && RemoteDirView);  RemoteDirView->DDAllowMove = !WinConfiguration->DDDisableMove;  RemoteDirView->DimmHiddenFiles = WinConfiguration->DimmHiddenFiles;  RemoteDirView->ShowHiddenFiles = WinConfiguration->ShowHiddenFiles;  RemoteDirView->FormatSizeBytes = WinConfiguration->FormatSizeBytes;  RemoteDirView->ShowInaccesibleDirectories = WinConfiguration->ShowInaccesibleDirectories;  RemoteDirView->NaturalOrderNumericalSorting = WinConfiguration->NaturalOrderNumericalSorting;  RemoteDirView->AlwaysSortDirectoriesByName = WinConfiguration->AlwaysSortDirectoriesByName;  UpdateRowSelect(RemoteDirView);  RemoteDriveView->DDAllowMove = !WinConfiguration->DDDisableMove;  RemoteDriveView->DimmHiddenDirs = WinConfiguration->DimmHiddenFiles;  RemoteDriveView->ShowHiddenDirs = WinConfiguration->ShowHiddenFiles;  RemoteDriveView->ShowInaccesibleDirectories = WinConfiguration->ShowInaccesibleDirectories;  RemoteDriveView->NaturalOrderNumericalSorting = WinConfiguration->NaturalOrderNumericalSorting;  UpdateSessionsPageControlHeight();  SetDockAllowDrag(!WinConfiguration->LockToolbars);  UpdateToolbarDisplayMode();  UpdateTransferList();  if (Terminal != NULL)  {    TransferPresetAutoSelect();  }  UpdateQueueView();  UpdateControls();  // this can be called even before constuctor finishes.  if (FEditorManager != NULL)  {    FEditorManager->ProcessFiles(FileConfigurationChanged, NULL);  }  // this can be called even before constuctor finishes.  if (FLocalEditors != NULL)  {    for (int Index = 0; Index < FLocalEditors->Count; Index++)    {      ReconfigureEditorForm(static_cast<TForm *>(FLocalEditors->Items[Index]));    }  }  if (ComponentVisible[fcCustomCommandsBand])  {    UpdateCustomCommandsToolbar();  }  // show only when keeping queue items forever,  // otherwise, it's enough to have it in the context menu  QueueDeleteAllDoneQueueToolbarItem->Visible =    WinConfiguration->QueueKeepDoneItems && (WinConfiguration->QueueKeepDoneItemsFor < 0);  if (FFileColorsCurrent != WinConfiguration->FileColors)  {    TFileColorData::LoadList(WinConfiguration->FileColors, FFileColors);    FFileColorsCurrent = WinConfiguration->FileColors;    FileColorsChanged();  }  if ((GetNewTabTab()->CaptionTruncation != GetNewTabTabCaptionTruncation()) &&      (FSessionColors != NULL))  {    SessionListChanged();  }  if (GlyphsModule->LargerToolbar != WinConfiguration->LargerToolbar)  {    GlyphsModule->LargerToolbar = WinConfiguration->LargerToolbar;    if (FSessionColors != NULL)    {      RegenerateSessionColorsImageList();      UpdateSessionsPageControlHeight();    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoFileColorsChanged(TCustomDirView * DirView){  DirView->OnGetItemColor = FFileColors.empty() ? TDirViewGetItemColorEvent(NULL) : TDirViewGetItemColorEvent(&DirViewGetItemColor);  DirView->Invalidate();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileColorsChanged(){  DoFileColorsChanged(RemoteDirView);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileConfigurationChanged(  const UnicodeString FileName, TEditedFileData * /*Data*/, TObject * Token,  void * /*Arg*/){  if (Token != NULL)  {    TForm * Editor = dynamic_cast<TForm*>(Token);    DebugAssert(Editor != NULL);    ReconfigureEditorForm(Editor);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::EnableDDTransferConfirmation(TObject * /*Sender*/){  WinConfiguration->DDTransferConfirmation = asOn;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CopyParamDialogAfter(  TTransferDirection /*Direction*/, bool /*Temp*/, const UnicodeString & /*TargetDirectory*/){  // noop}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::GetDoNotShowCopyDialogDefault(bool DragDrop){  return DragDrop && (WinConfiguration->DDTransferConfirmation == asAuto);}//---------------------------------------------------------------------------void TCustomScpExplorerForm::HandleDoNotShowCopyDialogAgain(bool DragDrop, bool DoNotShowAgain){  if (DoNotShowAgain)  {    if (DragDrop)    {      if (WinConfiguration->DDTransferConfirmation == asAuto)      {        PopupTrayBalloon(          NULL, LoadStr(DD_TRANSFER_CONFIRM_OFF2), qtInformation, NULL, 0, EnableDDTransferConfirmation, NULL);      }      WinConfiguration->DDTransferConfirmation = asOff;    }    else    {      WinConfiguration->ConfirmTransferring = false;    }  }  else  {    // User explicitly unchecked "do not show again",    // so show him the dialog the next time    if (DragDrop && (WinConfiguration->DDTransferConfirmation == asAuto))    {      WinConfiguration->DDTransferConfirmation = asOn;    }  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CopyParamDialog(  TTransferDirection Direction, TTransferType Type, bool Temp,  TStrings * FileList, UnicodeString & TargetDirectory, TGUICopyParamType & CopyParam,  bool Confirm, bool DragDrop, int Options){  bool Result = true;  DebugAssert(HasActiveTerminal());  // these parameters are known in advance  int Params =    FLAGMASK(Type == ttMove, cpDelete);  bool ToTemp = (Temp && (Direction == tdToLocal));  if (Result && Confirm && WinConfiguration->ConfirmTransferring)  {    bool DisableNewerOnly =      (!Terminal->IsCapable[fcNewerOnlyUpload] && (Direction == tdToRemote)) ||      ToTemp;    Options |=      FLAGMASK(ToTemp, coTemp) |      FLAGMASK(!Terminal->IsCapable[fcBackgroundTransfers], coDisableQueue) |      coDoNotShowAgain;    TUsableCopyParamAttrs UsableCopyParamAttrs = Terminal->UsableCopyParamAttrs(Params);    int CopyParamAttrs = (Direction == tdToRemote ?      UsableCopyParamAttrs.Upload : UsableCopyParamAttrs.Download) |      FLAGMASK(DisableNewerOnly, cpaNoNewerOnly);    int OutputOptions = FLAGMASK(GetDoNotShowCopyDialogDefault(DragDrop), cooDoNotShowAgain);    std::unique_ptr<TSessionData> SessionData(SessionDataForCode());    FlashOnBackground(); // Particularly when called from ClipboardFakeCreated    Result = DoCopyDialog(Direction == tdToRemote, Type == ttMove,      FileList, TargetDirectory, &CopyParam, Options, CopyParamAttrs, SessionData.get(), &OutputOptions, -1);    if (Result)    {      HandleDoNotShowCopyDialogAgain(DragDrop, FLAGSET(OutputOptions, cooDoNotShowAgain));      CopyParamDialogAfter(Direction, Temp, TargetDirectory);    }  }  if (Result && CopyParam.Queue && !ToTemp && Terminal->IsCapable[fcBackgroundTransfers])  {    Configuration->Usage->Inc(L"TransfersOnBackground");    // these parameter are known only after transfer dialog    Params |=      (CopyParam.QueueNoConfirmation ? cpNoConfirmation : 0);    AddQueueItem(Queue, Direction, FileList, TargetDirectory, CopyParam, Params);    Result = false;    ClearTransferSourceSelection(Direction);  }  return Result;}//---------------------------------------------------------------------------void TCustomScpExplorerForm::ClearOperationSelection(TOperationSide Side){  if (FOnFileOperationFinished != NULL)  {    FOnFileOperationFinished(Side, UnicodeString(), true);  }  else  {    if (HasDirView[Side])    {      DirView(Side)->SelectAll(smNone);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ClearTransferSourceSelection(TTransferDirection Direction){  TOperationSide Side = ((Direction == tdToRemote) ? osLocal : osRemote);  ClearOperationSelection(Side);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AddQueueItem(  TTerminalQueue * Queue, TTransferDirection Direction, TStrings * FileList,  const UnicodeString TargetDirectory, TGUICopyParamType & CopyParam,  int Params){  DebugAssert(Queue != NULL);  bool SingleFile = false;  if (FileList->Count == 1)  {    if (Direction == tdToRemote)    {      UnicodeString FileName = FileList->Strings[0];      SingleFile = FileExists(ApiPath(FileName));    }    else    {      TRemoteFile * File = static_cast<TRemoteFile *>(FileList->Objects[0]);      SingleFile = !File->IsDirectory;    }  }  TQueueItem * QueueItem;  if (Direction == tdToRemote)  {    CopyParam.IncludeFileMask.SetRoots(FileList, TargetDirectory);    QueueItem = new TUploadQueueItem(Terminal, FileList, TargetDirectory,      &CopyParam, Params, SingleFile, CopyParam.QueueParallel);  }  else  {    CopyParam.IncludeFileMask.SetRoots(TargetDirectory, FileList);    QueueItem = new TDownloadQueueItem(Terminal, FileList, TargetDirectory,      &CopyParam, Params, SingleFile, CopyParam.QueueParallel);  }  AddQueueItem(Queue, QueueItem, Terminal);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AddQueueItem(TTerminalQueue * Queue, TQueueItem * QueueItem, TManagedTerminal * Terminal){  if (Queue->IsEmpty)  {    Terminal->QueueOperationStart = Now();  }  Queue->AddItem(QueueItem);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RestoreFormParams(){}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::InitControls(){  DebugAssert(FDocks != NULL);  for (int Index = 0; Index < ComponentCount; Index++)  {    TTBDock * Dock = dynamic_cast<TTBDock *>(Components[Index]);    if ((Dock != NULL) && (Dock->Tag == 0))    {      FDocks->Add(Dock);    }  }  CollectItemsWithTextDisplayMode(this);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RestoreParams(){  ConfigurationChanged();  QueuePanel->Height =    LoadDimension(WinConfiguration->QueueView.Height, WinConfiguration->QueueView.HeightPixelsPerInch, this);  LoadListViewStr(QueueView3, WinConfiguration->QueueView.Layout);  QueueDock->Visible = WinConfiguration->QueueView.ToolBar;  QueueLabel->Visible = WinConfiguration->QueueView.Label;  QueueFileList->Visible = WinConfiguration->QueueView.FileList;  QueueFileList->Height =    LoadDimension(WinConfiguration->QueueView.FileListHeight, WinConfiguration->QueueView.FileListHeightPixelsPerInch, this);  if (QueueFileList->Visible)  {    AdjustQueueLayout();  }  UpdateCustomCommandsToolbar();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::StoreParams(){  int APixelsPerInch = GetControlPixelsPerInch(this);  WinConfiguration->QueueView.Height = QueuePanel->Height;  WinConfiguration->QueueView.HeightPixelsPerInch = APixelsPerInch;  WinConfiguration->QueueView.Layout = GetListViewStr(QueueView3);  WinConfiguration->QueueView.ToolBar = QueueDock->Visible;  WinConfiguration->QueueView.Label = QueueLabel->Visible;  WinConfiguration->QueueView.FileList = QueueFileList->Visible;  WinConfiguration->QueueView.FileListHeight = QueueFileList->Height;  WinConfiguration->QueueView.FileListHeightPixelsPerInch = APixelsPerInch;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CreateParams(TCreateParams & Params){  if (!FFormRestored)  {    FFormRestored = true;    RestoreFormParams();  }  TForm::CreateParams(Params);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetDockAllowDrag(bool value){  DebugAssert(FDocks != NULL);  for (int Index = 0; Index < FDocks->Count; Index++)  {    static_cast<TTBDock*>(FDocks->Items[Index])->AllowDrag = value;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LoadToolbarsLayoutStr(UnicodeString LayoutStr, UnicodeString ButtonsStr){  SetDockAllowDrag(true);  while (!ButtonsStr.IsEmpty())  {    UnicodeString S = CutToChar(ButtonsStr, L';', true);    UnicodeString Name = CutToChar(S, L'=', true);    for (int ToolbarIndex = 0; ToolbarIndex < ComponentCount; ToolbarIndex++)    {      TTBCustomToolbar * Toolbar = dynamic_cast<TTBCustomToolbar *>(Components[ToolbarIndex]);      if ((Toolbar != NULL) && SameText(Name, GetToolbarKey(Toolbar->Name)))      {        while (!S.IsEmpty())        {          UnicodeString S2 = CutToChar(S, L',', true);          UnicodeString Name = CutToChar(S2, L':', true);          for (int ItemIndex = 0; ItemIndex < Toolbar->Items->Count; ItemIndex++)          {            TTBCustomItem * Item = Toolbar->Items->Items[ItemIndex];            if (SameText(GetToolbarItemName(Item), Name))            {              // forward compatibility              UnicodeString S3 = CutToChar(S2, L':', true);              bool Visible = StrToIntDef(S3, 0);              Item->Visible = Visible;            }          }        }      }    }  }  ::LoadToolbarsLayoutStr(this, LayoutStr);  SetDockAllowDrag(!WinConfiguration->LockToolbars);}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::GetToolbarsLayoutStr(){  UnicodeString Result;  SetDockAllowDrag(true);  Result = ::GetToolbarsLayoutStr(this);  SetDockAllowDrag(!WinConfiguration->LockToolbars);  return Result;}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::GetToolbarItemName(TTBCustomItem * Item){  UnicodeString Result;  if (Item->Action != NULL)  {    Result = Item->Action->Name;    Result = RemoveSuffix(Result, L"Action", true);  }  else  {    Result = Item->Name;    Result = RemoveSuffix(Result, L"SubmenuItem", true);    Result = RemoveSuffix(Result, L"Item", true);  }  return Result;}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::GetToolbarsButtonsStr(){  UnicodeString Result;  for (int ToolbarIndex = 0; ToolbarIndex < ComponentCount; ToolbarIndex++)  {    UnicodeString ToolbarStr;    TTBCustomToolbar * Toolbar = dynamic_cast<TTBCustomToolbar *>(Components[ToolbarIndex]);    if ((Toolbar != NULL) && (Toolbar != QueueToolbar))    {      for (int ItemIndex = 0; ItemIndex < Toolbar->Items->Count; ItemIndex++)      {        TTBCustomItem * Item = Toolbar->Items->Items[ItemIndex];        // Currently all buttons are visible by default, so we can safely remember all hidden buttons.        // Once we introduce any buttons that are hidden by default, we would have to remember their initial state        // and save the changes here only.        if (NonVisualDataModule->IsCustomizableToolbarItem(Item) && !Item->Visible)        {          UnicodeString Name = GetToolbarItemName(Item);          DebugAssert(Name.Pos(L"TBX") == 0);          AddToList(ToolbarStr, FORMAT(L"%s:0", (Name)), L",");        }      }    }    if (!ToolbarStr.IsEmpty())    {      AddToList(Result, FORMAT(L"%s=%s", (GetToolbarKey(Toolbar->Name), ToolbarStr)), L";");    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CreateProgressForm(TSynchronizeProgress * SynchronizeProgress){  DebugAssert(FProgressForm == NULL);  bool AllowSkip = HasActiveTerminal() ? Terminal->IsCapable[fcSkipTransfer] : false;  bool AllowMoveToQueue = (FTransferResumeList != NULL) || (FDeletedFiles != NULL);  FProgressForm = new TProgressForm(Application, AllowMoveToQueue, AllowSkip, SynchronizeProgress);  FProgressForm->DeleteLocalToRecycleBin =    (WinConfiguration->DeleteToRecycleBin != FAlternativeDelete);  FProgressForm->DeleteRemoteToRecycleBin =    HasActiveTerminal() &&    (Terminal->SessionData->DeleteToRecycleBin != FAlternativeDelete) &&    !Terminal->SessionData->RecycleBinPath.IsEmpty();  // As progress window has delayed show now, we need to lock ourselves, (at least) until then  LockWindow();  // Actually, do not know what hides the progress once the operation finishes  // (it is possibly the SetQueueProgress - and we should not rely on that)  SetTaskbarListProgressState(TBPF_NORMAL);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DestroyProgressForm(){  UnlockWindow();  SAFE_DESTROY(FProgressForm);  SetQueueProgress();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileOperationProgress(  TFileOperationProgressType & ProgressData){  // Download to temporary local directory  if (FPendingTempSpaceWarn && ProgressData.InProgress && ProgressData.TotalSizeSet)  {    bool Continue = true;    FPendingTempSpaceWarn = false;    DoWarnLackOfTempSpace(ProgressData.Directory, ProgressData.TotalSize, Continue);    if (!Continue)    {      Abort();    }  }  // operation is being executed and we still didn't show up progress form  if (ProgressData.InProgress && !FProgressForm)  {    CreateProgressForm(NULL);    DebugAssert(FProgressForm->OnceDoneOperation == odoIdle);    FProgressForm->OnceDoneOperation = ProgressData.InitialOnceDoneOperation;  }  // operation is finished (or terminated), so we hide progress form  else if (!ProgressData.InProgress && (FProgressForm != NULL) && (FProgressForm->SynchronizeProgress == NULL))  {    DestroyProgressForm();    if (ProgressData.Operation == foCalculateSize)    {      // When calculating size before transfer, the abort caused by      // cancel flag set due to "MoveToQueue" below,      // is not propagated back to us in ExecuteFileOperation,      // as it is silently swallowed.      // So we explicitly (re)throw it here.      if (FMoveToQueue)      {        Abort();      }    }    else    {      if ((ProgressData.Cancel == csContinue) &&          !FAutoOperation)      {        OperationComplete(ProgressData.StartTime);      }    }  }  if (FProgressForm &&      // Can happen only during synchronization, when ending one of the operations      ProgressData.InProgress)  {    FProgressForm->SetProgressData(ProgressData);    DebugAssert(ProgressData.InProgress);    SetTaskbarListProgressValue(&ProgressData);    if (FProgressForm->Cancel > csContinue)    {      ProgressData.SetCancelAtLeast(FProgressForm->Cancel);      if (FProgressForm->Cancel == csCancelFile)      {        FProgressForm->ClearCancel();      }      // cancel cancels even the move      FMoveToQueue = false;    }    else if (FProgressForm->MoveToQueue)    {      FMoveToQueue = true;      ProgressData.SetCancelAtLeast(csCancel);    }    if ((FTransferResumeList != NULL) &&        ProgressData.InProgress &&        ProgressData.IsTransfer() &&        !ProgressData.FullFileName.IsEmpty())    {      if ((FTransferResumeList->Count == 0) ||          (FTransferResumeList->Strings[FTransferResumeList->Count - 1] != ProgressData.FullFileName))      {        // note that we do not recognize directories from files here        FTransferResumeList->Add(ProgressData.FullFileName);      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::OperationComplete(  const TDateTime & StartTime){  if (GUIConfiguration->BeepOnFinish &&      (Now() - StartTime > GUIConfiguration->BeepOnFinishAfter))  {    UnicodeString BeepSound = GUIConfiguration->BeepSound;    DWORD Sound;    if (!ExtractFileExt(BeepSound).IsEmpty())    {      Sound = SND_FILENAME;    }    else    {      Sound = SND_ALIAS;    }    PlaySound(BeepSound.c_str(), NULL, Sound | SND_ASYNC);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::OperationProgress(  TFileOperationProgressType & ProgressData){  // For example, when calling TFileOperationProgressType::Suspend in TTerminal::QueryReopen,  // we cannot recurse back to TTerminal::Idle as that may detect another error, calling "suspend" again.  TAutoNestingCounter Counter(FDoNotIdleCurrentTerminal);  FileOperationProgress(ProgressData);}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::GetProgressTitle(){  UnicodeString Result;  if (FProgressForm != NULL)  {    Result = FProgressForm->ProgressStr();  }  return Result;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::PanelOperation(TOperationSide /*Side*/,  bool DragDrop){  return (!DragDrop && (DropSourceControl == NULL)) ||    (DropSourceControl == DirView(osOther));}//---------------------------------------------------------------------------TListItem * TCustomScpExplorerForm::VisualiseOperationFinished(TOperationSide Side, const UnicodeString & FileName, bool Unselect){  TCustomDirView * ADirView = DirView(Side);  UnicodeString FileNameOnly = ExtractFileName(FileName, !IsSideLocalBrowser(Side));  TListItem * Item = ADirView->FindFileItem(FileNameOnly);  // this can happen when local drive is unplugged in the middle of the operation  if (Item != NULL)  {    if (Unselect)    {      Item->Selected = false;    }    ADirView->MakeProgressVisible(Item);  }  return Item;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoOperationFinished(  TFileOperation Operation, TOperationSide Side,  bool /*Temp*/, const UnicodeString & FileName, bool Success,  TOnceDoneOperation & OnceDoneOperation){  if (!FAutoOperation)  {    // no selection on "/upload", form serves only as event handler    // (it is not displayed)    if (PanelOperation(Side, FDragDropOperation) && Visible &&        ((Operation == FPrimaryOperation) ||         ((Operation != foCalculateSize) && (Operation != foGetProperties) && (Operation != foCalculateChecksum))))    {      TOperationSide DViewSide;      if ((FProgressSide != osCurrent) &&          IsLocalBrowserMode() && (Side == osLocal)) // Only to limit the impact      {        // assume the operation is over the focused panel        DViewSide = FProgressSide;      }      else      {        DViewSide = Side;      }      if (FOnFileOperationFinished != NULL)      {        FOnFileOperationFinished(DViewSide, FileName, Success);      }      else      {        VisualiseOperationFinished(DViewSide, FileName, Success);      }    }    if (TFileOperationProgressType::IsTransferOperation(Operation))    {      if (DebugAlwaysTrue(!IsLocalBrowserMode()))      {        if (Side == osLocal)        {          Configuration->Usage->Inc(L"UploadedFiles");        }        else        {          Configuration->Usage->Inc(L"DownloadedFiles");        }      }    }  }  if (Success && (FSynchronizeController != NULL))  {    DebugAssert(!IsSideLocalBrowser(osRemote));    if (Operation == foCopy)    {      DebugAssert(Side == osLocal);      FSynchronizeController->LogOperation(soUpload, FileName);    }    else if (Operation == foDelete)    {      DebugAssert(Side == osRemote);      FSynchronizeController->LogOperation(soDelete, FileName);    }  }  if (FProgressForm)  {    OnceDoneOperation = FProgressForm->OnceDoneOperation;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::OperationFinished(  TFileOperation Operation, TOperationSide Side,  bool Temp, const UnicodeString & FileName, Boolean Success,  TOnceDoneOperation & OnceDoneOperation){  TAutoNestingCounter Counter(FDoNotIdleCurrentTerminal);  DoOperationFinished(Operation, Side, Temp, FileName, Success,    OnceDoneOperation);}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::IsLocalBrowserMode(){  return false;}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::SupportsLocalBrowser(){  return false;}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::IsSideLocalBrowser(TOperationSide){  return false;}//---------------------------------------------------------------------------TCustomDirView * TCustomScpExplorerForm::GetCurrentLocalBrowser(){  return NULL;}//---------------------------------------------------------------------------TCustomDirView * __fastcall TCustomScpExplorerForm::DirView(TOperationSide Side){  DebugAssert(GetSide(Side) == osRemote);  DebugUsedParam(Side);  return RemoteDirView;}//---------------------------------------------------------------------------TCustomDriveView * __fastcall TCustomScpExplorerForm::DriveView(TOperationSide Side){  DebugAssert(GetSide(Side) == osRemote);  DebugUsedParam(Side);  return RemoteDriveView;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::DirViewEnabled(TOperationSide Side){  DebugAssert(GetSide(Side) == osRemote);  DebugUsedParam(Side);  return HasActiveTerminal();}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::GetEnableFocusedOperation(  TOperationSide Side, int FilesOnly){  return DirView(Side)->AnyFileSelected(true, (FilesOnly != 0), true);}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::GetEnableSelectedOperation(  TOperationSide Side, int FilesOnly){  return DirView(Side)->AnyFileSelected(false, (FilesOnly != 0), true);}//---------------------------------------------------------------------------struct THistoryItemData{  short int Side;  short int Index;};//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::HistoryGo(TOperationSide Side, int Index){  DirView(Side)->HistoryGo(Index);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::HistoryItemClick(System::TObject* Sender){  TTBCustomItem * Item = dynamic_cast<TTBCustomItem *>(Sender);  THistoryItemData Data = *reinterpret_cast<THistoryItemData*>(&(Item->Tag));  HistoryGo((TOperationSide)Data.Side, Data.Index);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateHistoryMenu(TOperationSide Side,  bool Back){  if (FHistoryMenu[Side == osLocal][Back] != NULL)  {    TCustomDirView * DView = DirView(Side);    TTBXPopupMenu * Menu = FHistoryMenu[Side == osLocal][Back];    int ICount = Back ? DView->BackCount : DView->ForwardCount;    if (ICount > 10)    {      ICount = 10;    }    Menu->Items->Clear();    THistoryItemData Data;    Data.Side = Side;    for (short int i = 1; i <= ICount; i++)    {      TTBCustomItem * Item = new TTBXItem(Menu);      Data.Index = static_cast<short int>(i * (Back ? -1 : 1));      Item->Caption = MinimizeName(DView->HistoryPath[Data.Index], 50, !IsSideLocalBrowser(Side));      Item->Hint = DView->HistoryPath[Data.Index];      DebugAssert(sizeof(int) == sizeof(THistoryItemData));      Item->Tag = *reinterpret_cast<int*>(&Data);      Item->OnClick = HistoryItemClick;      Menu->Items->Add(Item);    }  }}//---------------------------------------------------------------------------TTBXPopupMenu * __fastcall TCustomScpExplorerForm::HistoryMenu(  TOperationSide Side, bool Back){  if (FHistoryMenu[Side == osLocal][Back] == NULL)  {    // workaround    // In Pascal the size of TTBXPopupMenu is 132, in C++ 136,    // operator new allocates memory in Pascal code, but calls inline    // constructor in C++, leading in problems, the function does    // both in Pascal code    FHistoryMenu[Side == osLocal][Back] = CreateTBXPopupMenu(this);    UpdateHistoryMenu(Side, Back);  }  return FHistoryMenu[Side == osLocal][Back];}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewHistoryChange(      TCustomDirView *Sender){  TOperationSide Side = (Sender == DirView(osOther) ? osOther : osLocal);  UpdateHistoryMenu(Side, true);  UpdateHistoryMenu(Side, false);}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CustomCommandRemoteAllowed(){  // remote custom commands can be executed only if the server supports shell commands  // or have secondary shell  return HasActiveTerminal() && (Terminal->IsCapable[fcSecondaryShell] || Terminal->IsCapable[fcShellAnyCommand]);}//---------------------------------------------------------------------------int __fastcall TCustomScpExplorerForm::CustomCommandState(  const TCustomCommandType & Command, bool OnFocused, TCustomCommandListType ListType){  // -1 = hidden, 0 = disabled, 1 = enabled  int Result;  TFileCustomCommand RemoteCustomCommand;  TLocalCustomCommand LocalCustomCommand;  TFileCustomCommand * NonInteractiveCustomCommand =    FLAGCLEAR(Command.Params, ccLocal) ? &RemoteCustomCommand : &LocalCustomCommand;  TInteractiveCustomCommand InteractiveCustomCommand(NonInteractiveCustomCommand);  UnicodeString Cmd = InteractiveCustomCommand.Complete(Command.Command, false);  if (FLAGCLEAR(Command.Params, ccLocal))  {    int AllowedState = CustomCommandRemoteAllowed() ? 1 : 0;    // custom command that does not operate with files can be executed anytime ...    if (!NonInteractiveCustomCommand->IsFileCommand(Cmd))    {      // ... but do not show such command in remote file menu      if ((ListType == ccltAll) || (ListType == ccltNonFile))      {        Result = AllowedState;      }      else      {        Result = -1;      }    }    else    {      if ((ListType == ccltAll) || ((ListType == ccltFile) && !IsSideLocalBrowser(FCurrentSide)))      {        Result = (DirView(FCurrentSide)->AnyFileSelected(OnFocused, false, true)) ? AllowedState : 0;      }      else      {        Result = -1;      }    }  }  else  {    // custom command that does not operate with files can be executed anytime    if (!NonInteractiveCustomCommand->IsFileCommand(Cmd))    {      Result = ((ListType == ccltAll) || (ListType == ccltNonFile)) ? 1 : -1;    }    else if (LocalCustomCommand.HasLocalFileName(Cmd))    {      if ((ListType == ccltAll) || (ListType == ccltFile))      {        // special case is "diff"-style command that can be executed over any side,        // if we have both sides        Result =          // Cannot have focus on both panels, so we have to call AnyFileSelected          // directly (instead of EnableSelectedOperation) to pass          // false to FocusedFileOnlyWhenFocused when panel is inactive.          ((HasDirView[osLocal] && !IsSideLocalBrowser(osRemote) &&            DirView(osLocal)->AnyFileSelected(false, false, (FCurrentSide == osLocal))) &&            DirView(osRemote)->AnyFileSelected(false, false, (FCurrentSide == osRemote))) ? 1 : 0;      }      else if (ListType == ccltBoth)      {        DebugAssert(!IsLocalBrowserMode());        Result = 1;      }      else      {        Result = -1;      }    }    else    {      if ((ListType == ccltAll) ||          ((ListType == ccltFile) && (!IsSideLocalBrowser(FCurrentSide) || FLAGCLEAR(Command.Params, ccRemoteFiles))))      {        Result = DirView(FCurrentSide)->AnyFileSelected(OnFocused, false, true) ? 1 : 0;      }      else      {        Result = -1;      }    }    if ((Result > 0) &&        LocalCustomCommand.IsSessionCommand(Cmd) &&        !HasActiveTerminal())    {      Result = 0;    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteCustomCommand(  TStrings * FileList, const TCustomCommandType & ACommand,  const TCustomCommandData & Data, const UnicodeString & CommandCommand){  if (EnsureCommandSessionFallback(fcShellAnyCommand))  {    TRemoteCustomCommand RemoteCustomCommand(Data, Terminal->CurrentDirectory);    TWinInteractiveCustomCommand InteractiveCustomCommand(      &RemoteCustomCommand, ACommand.Name, ACommand.HomePage);    UnicodeString Command = InteractiveCustomCommand.Complete(CommandCommand, false);    Configuration->Usage->Inc(L"RemoteCustomCommandRuns2");    bool Capture =      FLAGSET(ACommand.Params, ccShowResults) ||      FLAGSET(ACommand.Params, ccCopyResults) ||      FLAGSET(ACommand.Params, ccShowResultsInMsgBox);    TCaptureOutputEvent OutputEvent = NULL;    DebugAssert(FCapturedLog == NULL);    if (Capture)    {      FCapturedLog = new TStringList();      OutputEvent = TerminalCaptureLog;    }    try    {      if (!RemoteCustomCommand.IsFileCommand(Command))      {        Terminal->AnyCommand(RemoteCustomCommand.Complete(Command, true),          OutputEvent);      }      else      {        Terminal->CustomCommandOnFiles(Command, ACommand.Params, FileList, OutputEvent);      }      if ((FCapturedLog != NULL) && (FCapturedLog->Count > 0))      {        if (FLAGSET(ACommand.Params, ccCopyResults))        {          CopyToClipboard(FCapturedLog);        }        if (FLAGSET(ACommand.Params, ccShowResults))        {          DoConsoleDialog(Terminal, L"", FCapturedLog);        }        else if (FLAGSET(ACommand.Params, ccShowResultsInMsgBox))        {          MessageDialog(FCapturedLog->Text, qtInformation, qaOK);        }      }    }    __finally    {      SAFE_DESTROY(FCapturedLog);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LocalCustomCommandPure(  TStrings * FileList, const TCustomCommandType & ACommand, const UnicodeString & Command, TStrings * ALocalFileList,  const TCustomCommandData & Data, bool LocalFileCommand, bool FileListCommand, UnicodeString * POutput){  DebugAssert(!IsLocalBrowserMode());  TStrings * LocalFileList = NULL;  TStrings * RemoteFileList = NULL;  TStrings * RemoteFileListFull = NULL;  try  {    if (LocalFileCommand)    {      if (ALocalFileList == NULL)      {        DebugAssert(HasDirView[osLocal]);        // Cannot have focus on both panels, so we have to call AnyFileSelected        // directly (instead of EnableSelectedOperation) to pass        // false to FocusedFileOnlyWhenFocused        DebugAssert(DirView(osLocal)->AnyFileSelected(false, false, false));        LocalFileList = DirView(osLocal)->CreateFileList(false, true, NULL);      }      else      {        LocalFileList = ALocalFileList;      }      if (FileListCommand)      {        if (LocalFileList->Count != 1)        {          throw Exception(LoadStr(CUSTOM_COMMAND_SELECTED_UNMATCH1));        }      }      else      {        if ((LocalFileList->Count != 1) &&            (FileList->Count != 1) &&            (LocalFileList->Count != FileList->Count))        {          throw Exception(LoadStr(CUSTOM_COMMAND_SELECTED_UNMATCH));        }      }    }    UnicodeString RootTempDir;    UnicodeString TempDir;    bool RemoteFiles = FLAGSET(ACommand.Params, ccRemoteFiles);    if (!RemoteFiles)    {      TemporarilyDownloadFiles(FileList, false, RootTempDir, TempDir, false, true, true);    }    try    {      TDateTimes RemoteFileTimes;      if (RemoteFiles)      {        RemoteFileList = FileList;      }      else      {        RemoteFileList = new TStringList();        TMakeLocalFileListParams MakeFileListParam;        MakeFileListParam.FileList = RemoteFileList;        MakeFileListParam.FileTimes = &RemoteFileTimes;        MakeFileListParam.IncludeDirs = FLAGSET(ACommand.Params, ccApplyToDirectories);        MakeFileListParam.Recursive =          FLAGSET(ACommand.Params, ccRecursive) && !FileListCommand;        ProcessLocalDirectory(TempDir, Terminal->MakeLocalFileList, &MakeFileListParam);        if (!MakeFileListParam.Recursive)        {          RemoteFileTimes.clear();          RemoteFileListFull = new TStringList();          MakeFileListParam.FileList = RemoteFileListFull;          MakeFileListParam.Recursive = true;          MakeFileListParam.IncludeDirs = false;          ProcessLocalDirectory(TempDir, Terminal->MakeLocalFileList, &MakeFileListParam);        }        else        {          RemoteFileListFull = RemoteFileList;        }      }      bool NonBlocking = FileListCommand && RemoteFiles && !POutput;      TFileOperationProgressType Progress(&OperationProgress, &OperationFinished);      if (!NonBlocking)      {        int Count;        if (FileListCommand)        {          Count = 1;        }        else if (LocalFileCommand)        {          Count = std::max(LocalFileList->Count, RemoteFileList->Count);        }        else        {          Count = RemoteFileList->Count;        }        Progress.Start(foCustomCommand, osRemote, Count);        DebugAssert(FProgressForm != NULL);        FProgressForm->ReadOnly = true;      }      try      {        if (FileListCommand)        {          UnicodeString LocalFile;          // MakeFileList does not delimit filenames          UnicodeString FileList = MakeFileList(RemoteFileList);          if (LocalFileCommand)          {            DebugAssert(LocalFileList->Count == 1);            LocalFile = LocalFileList->Strings[0];          }          TLocalCustomCommand CustomCommand(Data,            Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(), L"", LocalFile, FileList);          UnicodeString ShellCommand = CustomCommand.Complete(Command, true);          if (NonBlocking)          {            DebugAssert(!POutput);            ExecuteShellChecked(ShellCommand);          }          else          {            ExecuteProcessCheckedAndWait(ShellCommand, HelpKeyword, POutput);          }        }        else if (LocalFileCommand)        {          if (LocalFileList->Count == 1)          {            UnicodeString LocalFile = LocalFileList->Strings[0];            for (int Index = 0; Index < RemoteFileList->Count; Index++)            {              UnicodeString FileName = RemoteFileList->Strings[Index];              UnicodeString FileNameForProgress = RemoteFiles ? FileName : ExtractFileName(FileName);              Progress.SetFile(FileNameForProgress);              TLocalCustomCommand CustomCommand(Data,                Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(), FileName, LocalFile, L"");              ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), HelpKeyword, POutput);              TOnceDoneOperation OnceDoneOperation;              // Do not unselect anything, as it won't work with two panels anyway              Progress.Finish(UnicodeString(), true, OnceDoneOperation);            }          }          else if (RemoteFileList->Count == 1)          {            UnicodeString FileName = RemoteFileList->Strings[0];            for (int Index = 0; Index < LocalFileList->Count; Index++)            {              UnicodeString LocalFileName = LocalFileList->Strings[Index];              UnicodeString LocalFileNameOnly = ExtractFileName(LocalFileName);              Progress.SetFile(LocalFileNameOnly);              TLocalCustomCommand CustomCommand(                Data, Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(),                FileName, LocalFileName, L"");              ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), HelpKeyword, POutput);              TOnceDoneOperation OnceDoneOperation;              // Do not unselect anything, as it won't work with two panels anyway              Progress.Finish(UnicodeString(), true, OnceDoneOperation);            }          }          else          {            if (LocalFileList->Count != RemoteFileList->Count)            {              throw Exception(LoadStr(CUSTOM_COMMAND_PAIRS_DOWNLOAD_FAILED));            }            for (int Index = 0; Index < LocalFileList->Count; Index++)            {              UnicodeString FileName = RemoteFileList->Strings[Index];              UnicodeString LocalFileName = LocalFileList->Strings[Index];              UnicodeString LocalFileNameOnly = ExtractFileName(LocalFileName);              Progress.SetFile(LocalFileNameOnly); // sic              TLocalCustomCommand CustomCommand(                Data, Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(),                FileName, LocalFileName, L"");              ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), HelpKeyword, POutput);              TOnceDoneOperation OnceDoneOperation;              // Do not unselect anything, as it won't work with two panels anyway              Progress.Finish(UnicodeString(), true, OnceDoneOperation);            }          }        }        else        {          for (int Index = 0; Index < RemoteFileList->Count; Index++)          {            UnicodeString FileName = RemoteFileList->Strings[Index];            UnicodeString FileNameForProgress = RemoteFiles ? FileName : ExtractFileName(FileName);            Progress.SetFile(FileNameForProgress);            TLocalCustomCommand CustomCommand(Data,              Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(),              FileName, L"", L"");            ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), HelpKeyword, POutput);            TOnceDoneOperation OnceDoneOperation;            Progress.Finish(FileNameForProgress, true, OnceDoneOperation);          }        }      }      __finally      {        if (!NonBlocking)        {          Progress.Stop();        }      }      DebugAssert(!FAutoOperation);      if (!RemoteFiles)      {        TempDir = IncludeTrailingBackslash(TempDir);        for (int Index = 0; Index < RemoteFileListFull->Count; Index++)        {          UnicodeString FileName = RemoteFileListFull->Strings[Index];          if (DebugAlwaysTrue(SameText(TempDir, FileName.SubString(1, TempDir.Length()))) &&              // Skip directories, process only nested files.              // The check is redundant as FileAge fails for directories anyway.              !DirectoryExists(FileName))          {            UnicodeString RemoteDir =              UnixExtractFileDir(                UnixIncludeTrailingBackslash(Terminal->CurrentDirectory) +                ToUnixPath(FileName.SubString(TempDir.Length() + 1, FileName.Length() - TempDir.Length())));            TSearchRecSmart SearchRec;            if (FileSearchRec(FileName, SearchRec) &&                (SearchRec.GetLastWriteTime() != RemoteFileTimes[Index]))            {              TGUICopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;              TemporaryFileCopyParam(CopyParam);              CopyParam.FileMask = L"";              FAutoOperation = true;              FMoveToQueue = false;              std::unique_ptr<TStrings> TemporaryFilesList(new TStringList());              TemporaryFilesList->Add(FileName);              Terminal->CopyToRemote(TemporaryFilesList.get(), RemoteDir, &CopyParam, cpTemporary, NULL);            }          }        }      }    }    __finally    {      FAutoOperation = false;      if (!RootTempDir.IsEmpty() && DebugAlwaysTrue(!RemoteFiles))      {        RecursiveDeleteFile(ExcludeTrailingBackslash(RootTempDir));      }    }  }  __finally  {    if (RemoteFileList != FileList)    {      delete RemoteFileList;    }    if (LocalFileList != ALocalFileList)    {      delete LocalFileList;    }    if (RemoteFileListFull != RemoteFileList)    {      delete RemoteFileListFull;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LocalCustomCommandWithLocalFiles(  const TCustomCommandType & ACommand, const UnicodeString & Command, const TCustomCommandData & Data,  bool FileListCommand, UnicodeString * POutput){  std::unique_ptr<TStrings> SelectedFileList(DirView(osCurrent)->CreateFileList(false, true, NULL));  std::unique_ptr<TStrings> LocalFileList(new TStringList());  for (int Index = 0; Index < SelectedFileList->Count; Index++)  {    UnicodeString FileName = SelectedFileList->Strings[Index];    if (DirectoryExists(FileName))    {      if (FLAGSET(ACommand.Params, ccApplyToDirectories))      {        LocalFileList->Add(FileName);      }      if (FLAGSET(ACommand.Params, ccRecursive))      {        TMakeLocalFileListParams MakeFileListParam;        MakeFileListParam.FileList = LocalFileList.get();        MakeFileListParam.FileTimes = NULL;        MakeFileListParam.IncludeDirs = FLAGSET(ACommand.Params, ccApplyToDirectories);        MakeFileListParam.Recursive = true;        ProcessLocalDirectory(FileName, Terminal->MakeLocalFileList, &MakeFileListParam);      }    }    else    {      LocalFileList->Add(FileName);    }  }  UnicodeString RemotePath;  if (Terminal != NULL)  {    RemotePath = Terminal->CurrentDirectory;  }  if (FileListCommand)  {    UnicodeString FileList = MakeFileList(LocalFileList.get());    TLocalCustomCommand CustomCommand(      Data, RemotePath, DefaultDownloadTargetDirectory(),      L"", L"", FileList);    ExecuteProcessChecked(CustomCommand.Complete(Command, true), HelpKeyword, POutput);  }  else  {    TFileOperationProgressType Progress(&OperationProgress, &OperationFinished);    Progress.Start(foCustomCommand, osLocal, LocalFileList->Count);    DebugAssert(FProgressForm != NULL);    FProgressForm->ReadOnly = true;    try    {      for (int Index = 0; Index < LocalFileList->Count; Index++)      {        UnicodeString FileName = LocalFileList->Strings[Index];        Progress.SetFile(FileName);        TLocalCustomCommand CustomCommand(          Data, RemotePath, DefaultDownloadTargetDirectory(),          FileName, L"", L"");        ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), HelpKeyword, POutput);        TOnceDoneOperation OnceDoneOperation;        Progress.Finish(FileName, true, OnceDoneOperation);      }    }    __finally    {      Progress.Stop();    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LocalCustomCommand(TStrings * FileList,  const TCustomCommandType & ACommand, TStrings * ALocalFileList,  const TCustomCommandData & Data, const UnicodeString & CommandCommand){  UnicodeString RemotePath = (Terminal != NULL) ? Terminal->CurrentDirectory : UnicodeString();  TLocalCustomCommand LocalCustomCommand(Data, RemotePath, DefaultDownloadTargetDirectory());  TWinInteractiveCustomCommand InteractiveCustomCommand(    &LocalCustomCommand, ACommand.Name, ACommand.HomePage);  UnicodeString Command = InteractiveCustomCommand.Complete(CommandCommand, false);  bool FileListCommand = LocalCustomCommand.IsFileListCommand(Command);  bool LocalFileCommand = LocalCustomCommand.HasLocalFileName(Command);  Configuration->Usage->Inc(L"LocalCustomCommandRuns2");  std::unique_ptr<UnicodeString> POutput;  if (FLAGSET(ACommand.Params, ccShowResultsInMsgBox) ||      FLAGSET(ACommand.Params, ccCopyResults))  {    POutput.reset(new UnicodeString());  }  TValueRestorer<TOperationSide> ProgressSideRestorer(FProgressSide, FCurrentSide);  if (!LocalCustomCommand.IsFileCommand(Command))  {    ExecuteProcessChecked(LocalCustomCommand.Complete(Command, true), HelpKeyword, POutput.get());  }  // remote files?  else if (!IsSideLocalBrowser(FCurrentSide) || LocalFileCommand)  {    LocalCustomCommandPure(FileList, ACommand, Command, ALocalFileList, Data, LocalFileCommand, FileListCommand, POutput.get());  }  // local files  else  {    LocalCustomCommandWithLocalFiles(ACommand, Command, Data, FileListCommand, POutput.get());  }  if (POutput.get() != NULL)  {    // If the output is single-line, we do not want the trailing CRLF, as the CopyToClipboard(TStrings *) does    int P = POutput->Pos(sLineBreak);    if (P == POutput->Length() - static_cast<int>(strlen(sLineBreak)) + 1)    {      POutput->SetLength(P - 1);    }    // Copy even empty output to clipboard    if (FLAGSET(ACommand.Params, ccCopyResults))    {      CopyToClipboard(*POutput);    }    // But do not show an empty message box.    // This way the ShowResultsInMsgBox can be used to suppress a console window of commands with no output    if (FLAGSET(ACommand.Params, ccShowResultsInMsgBox) &&        !POutput->IsEmpty())    {      TClipboardHandler ClipboardHandler;      ClipboardHandler.Text = *POutput;      TMessageParams Params;      TQueryButtonAlias Aliases[1];      Aliases[0].Button = qaRetry;      Aliases[0].Alias = LoadStr(EDIT_COPY);      Aliases[0].OnSubmit = &ClipboardHandler.Copy;      Params.Aliases = Aliases;      Params.AliasesCount = LENOF(Aliases);      MessageDialog(*POutput, qtInformation, qaOK | qaRetry, HelpKeyword, &Params);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,  const TCustomCommandType & ACommand, TStrings * ALocalFileList){  TCustomCommandData Data;  UnicodeString Site;  UnicodeString RemotePath;  if (HasActiveTerminal())  {    std::unique_ptr<TSessionData> SessionData(SessionDataForCode());    Data = TCustomCommandData(SessionData.get());    Site = Terminal->SessionData->SessionKey;    RemotePath = Terminal->CurrentDirectory;  }  UnicodeString HelpKeyword = ACommand.HomePage;  std::unique_ptr<TStrings> CustomCommandOptions(CloneStrings(WinConfiguration->CustomCommandOptions));  if (ACommand.AnyOptionWithFlag(TCustomCommandType::ofRun))  {    std::unique_ptr<TCustomCommand> CustomCommandForOptions;    if (FLAGCLEAR(ACommand.Params, ccLocal))    {      CustomCommandForOptions.reset(new TRemoteCustomCommand(Data, RemotePath));    }    else    {      CustomCommandForOptions.reset(new TLocalCustomCommand(Data, RemotePath, DefaultDownloadTargetDirectory()));    }    if (!DoCustomCommandOptionsDialog(           &ACommand, CustomCommandOptions.get(), NULL, TCustomCommandType::ofRun, CustomCommandForOptions.get(), Site, NULL))    {      Abort();    }  }  UnicodeString CommandCommand = ACommand.GetCommandWithExpandedOptions(CustomCommandOptions.get(), Site);  if (FLAGCLEAR(ACommand.Params, ccLocal))  {    RemoteCustomCommand(FileList, ACommand, Data, CommandCommand);  }  else  {    LocalCustomCommand(FileList, ACommand, ALocalFileList, Data, CommandCommand);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::BothCustomCommand(  const TCustomCommandType & Command){  DebugAssert(FCustomCommandLocalFileList != NULL);  DebugAssert(FCustomCommandRemoteFileList != NULL);  DebugAssert(FCustomCommandLocalFileList->Count == FCustomCommandRemoteFileList->Count);  TStrings * LocalFileList = new TStringList();  TStrings * RemoteFileList = new TStringList();  try  {    for (int Index = 0; Index < FCustomCommandLocalFileList->Count; Index++)    {      LocalFileList->Clear();      LocalFileList->AddObject(        FCustomCommandLocalFileList->Strings[Index],        FCustomCommandLocalFileList->Objects[Index]);      RemoteFileList->Clear();      RemoteFileList->AddObject(        FCustomCommandRemoteFileList->Strings[Index],        FCustomCommandRemoteFileList->Objects[Index]);      CustomCommand(RemoteFileList, Command, LocalFileList);    }  }  __finally  {    delete LocalFileList;    delete RemoteFileList;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CustomCommandMenu(  TAction * Action, TStrings * LocalFileList, TStrings * RemoteFileList){  delete FCustomCommandLocalFileList;  delete FCustomCommandRemoteFileList;  // takeover ownership,  // the lists must survive the MenuPopup as OnClick occurs only after it exits  FCustomCommandLocalFileList = LocalFileList;  FCustomCommandRemoteFileList = RemoteFileList;  TButton * Button = dynamic_cast<TButton *>(Action->ActionComponent);  if (Button != NULL)  {    FCustomCommandMenu->Items->Clear();    NonVisualDataModule->CreateCustomCommandsMenu(FCustomCommandMenu->Items, false, false, ccltBoth, NULL);    MenuPopup(FCustomCommandMenu, Button);  }  else  {    NonVisualDataModule->CreateCustomCommandsMenu(Action, false, ccltBoth);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TerminalCaptureLog(  const UnicodeString & AddedLine, TCaptureOutputType OutputType){  DebugAssert(FCapturedLog != NULL);  if ((OutputType == cotOutput) || (OutputType == cotError))  {    FCapturedLog->Add(AddedLine);  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::IsFileControl(TObject * Control,  TOperationSide Side){  return    (Side == osOther) &&    ((Control == DirView(osOther)) || (Control == DriveView(osOther)));}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewContextPopupDefaultItem(  TOperationSide Side, TTBXCustomItem * Item,  TResolvedDoubleClickAction DoubleClickAction1, TResolvedDoubleClickAction DoubleClickAction2){  TCustomDirView * DView = DirView(Side);  bool IsDefault = false;  if (DView->ItemFocused != NULL)  {    TTerminal * ATerminal = !IsSideLocalBrowser(Side) ? Terminal : NULL;    TResolvedDoubleClickAction DefaultAction =      WinConfiguration->ResolveDoubleClickAction(DView->ItemIsDirectory(DView->ItemFocused), ATerminal);    IsDefault = (DefaultAction == DoubleClickAction1) || (DefaultAction == DoubleClickAction2);  }  TTBItemOptions O = Item->Options;  if (IsDefault)  {    Item->Options = O << tboDefault;  }  else  {    Item->Options = O >> tboDefault;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewContextPopup(  TOperationSide Side, Byte PopupComponent, const TPoint &MousePos){  TCustomDirView * DView = DirView(Side);  TListItem * Item = DView->ItemFocused;  if ((DView->GetItemAt(MousePos.x, MousePos.y) == Item) &&      EnableFocusedOperation[Side])  {    TPoint ClientPoint;    ClientPoint = ((MousePos.x < 0) && (MousePos.y < 0)) ?      TPoint(0, 0) : MousePos;    FLastContextPopupScreenPoint = DView->ClientToScreen(ClientPoint);    reinterpret_cast<TPopupMenu*>(GetComponent(PopupComponent))->Popup(      FLastContextPopupScreenPoint.x, FLastContextPopupScreenPoint.y);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteDirViewContextPopup(      TObject * /*Sender*/, const TPoint &MousePos, bool &Handled){  DirViewContextPopupDefaultItem(osRemote, NonVisualDataModule->RemoteOpenMenuItem, rdcaChangeDir, rdcaOpen);  DirViewContextPopupDefaultItem(osRemote, NonVisualDataModule->RemoteEditMenuItem, rdcaEdit, rdcaNone);  DirViewContextPopupDefaultItem(osRemote, NonVisualDataModule->RemoteCopyMenuItem, rdcaCopy, rdcaNone);  DirViewContextPopup(osRemote, fcRemotePopup, MousePos);  Handled = true;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ReloadLocalDirectory(const UnicodeString Directory){}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::BatchStart(void *& /*Storage*/){  DebugAssert(FErrorList == NULL);  if (WinConfiguration->ContinueOnError)  {    FErrorList = new TStringList();    Configuration->Usage->Inc(L"ContinuationsOnError");  }  NonVisualDataModule->StartBusy();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::BatchEnd(void * /*Storage*/){  NonVisualDataModule->EndBusy();  if (FErrorList)  {    HandleErrorList(FErrorList);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateCopyParamCounters(  const TCopyParamType & CopyParam){  if (!CopyParam.IncludeFileMask.Masks.IsEmpty())  {    Configuration->Usage->Inc(L"FileMaskUses");  }  if (IsEffectiveFileNameMask(CopyParam.FileMask))  {    Configuration->Usage->Inc(L"OperationMaskUses");  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::ExecuteCopyMoveFileOperation(  TFileOperation Operation, TOperationSide Side, TStrings * FileList, bool NoConfirmation, void * AParam){  DebugAssert(!IsLocalBrowserMode());  TTransferDirection Direction = (Side == osLocal ? tdToRemote : tdToLocal);  TTransferType Type = (Operation == foCopy ? ttCopy : ttMove);  TTransferOperationParam DefaultParam;  TTransferOperationParam & Param = (AParam != NULL) ? *static_cast<TTransferOperationParam *>(AParam) : DefaultParam;  TGUICopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;  switch (Param.Queue)  {    case asOn:      CopyParam.Queue = true;      break;    case asOff:      CopyParam.Queue = false;      break;    case asAuto:    default:      // keep default      break;  }  bool Result =    CopyParamDialog(Direction, Type, Param.Temp, FileList, Param.TargetDirectory, CopyParam, !NoConfirmation, Param.DragDrop, Param.Options);  if (Result)  {    DebugAssert(Terminal);    bool SelectionRestored = false;    TCustomDirView * DView = NULL;    if (HasDirView[Side])    {      DView = DirView(Side);      DView->SaveSelection();      DView->SaveSelectedNames();    }    UpdateCopyParamCounters(CopyParam);    std::unique_ptr<TStringList> TransferResumeList(new TStringList());    DebugAssert(FTransferResumeList == NULL);    FTransferResumeList = Terminal->IsCapable[fcMoveToQueue] ? TransferResumeList.get() : NULL;    FMoveToQueue = false;    int Params = FLAGMASK(Operation == foMove, cpDelete);    try    {      TStrings * PermanentFileList;      std::unique_ptr<TStrings> PermanentFileListOwner;      try      {        if (Side == osLocal)        {          PermanentFileList = FileList;          Params |= FLAGMASK(Param.Temp, cpTemporary);          CopyParam.IncludeFileMask.SetRoots(FileList, Param.TargetDirectory);          Terminal->CopyToRemote(FileList, Param.TargetDirectory, &CopyParam, Params, NULL);          if (Operation == foMove)          {            ReloadLocalDirectory();            if (DView != NULL)            {              DView->RestoreSelection();            }            SelectionRestored = true;          }        }        else        {          // Clone the file list as it may refer to current directory files,          // which get destroyed, when the source directory is reloaded after foMove operation.          // We should actually clone the file list for whole ExecuteFileOperation to protect against reloads.          // But for a hotfix, we are not going to do such a big change.          PermanentFileListOwner.reset(TRemoteFileList::CloneStrings(FileList));          PermanentFileList = PermanentFileListOwner.get();          try          {            CopyParam.IncludeFileMask.SetRoots(Param.TargetDirectory, FileList);            Terminal->CopyToLocal(FileList, Param.TargetDirectory, &CopyParam, Params, NULL);          }          __finally          {            if (Operation == foMove)            {              if (DView != NULL)              {                DView->RestoreSelection();              }              SelectionRestored = true;            }            ReloadLocalDirectory(Param.TargetDirectory);          }        }        // When the transfer batch is aborted between individual file transfers, the Abort is not called.        if (FMoveToQueue)        {          Abort();        }      }      catch (EAbort &)      {        if (FMoveToQueue)        {          Params |= (CopyParam.QueueNoConfirmation ? cpNoConfirmation : 0);          DebugAssert(CopyParam.TransferSkipList == NULL);          DebugAssert(CopyParam.TransferResumeFile.IsEmpty());          if (TransferResumeList->Count > 0)          {            CopyParam.TransferResumeFile = TransferResumeList->Strings[TransferResumeList->Count - 1];            TransferResumeList->Delete(TransferResumeList->Count - 1);          }          CopyParam.TransferSkipList = TransferResumeList.release();          // not really needed, just to keep it consistent with TransferResumeList          FTransferResumeList = NULL;          FMoveToQueue = false;          Configuration->Usage->Inc("MovesToBackground");          AddQueueItem(Queue, Direction, PermanentFileList, Param.TargetDirectory, CopyParam, Params);          ClearTransferSourceSelection(Direction);        }        throw;      }    }    __finally    {      if (!SelectionRestored && (DView != NULL))      {        DView->DiscardSavedSelection();      }      FTransferResumeList = NULL;    }  }  return Result;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::ExecuteDeleteFileOperation(  TOperationSide Side, TStrings * FileList, void * Param){  DebugAssert(FileList->Count);  // We deliberately do not toggle alternative flag (Param), but use OR,  // because the Param is set only when command is invoked using Shift-Del/F8 keyboard  // shortcut of CurrentDeleteAlternativeAction  bool Alternative =    bool(Param) || UseAlternativeFunction();  bool Recycle;  if (IsSideLocalBrowser(Side))  {    Recycle = (WinConfiguration->DeleteToRecycleBin != Alternative);  }  else  {    Recycle =      (Terminal->SessionData->DeleteToRecycleBin != Alternative) &&      !Terminal->SessionData->RecycleBinPath.IsEmpty() &&      !Terminal->IsRecycledFile(FileList->Strings[0]);  }  bool Result = !(Recycle ? WinConfiguration->ConfirmRecycling : WinConfiguration->ConfirmDeleting);  if (!Result)  {    UnicodeString Query;    if (FileList->Count == 1)    {      if (IsSideLocalBrowser(Side))      {        Query = ExtractFileName(FileList->Strings[0]);      }      else      {        Query = UnixExtractFileName(FileList->Strings[0]);      }      Query = FMTLOAD((Recycle ? CONFIRM_RECYCLE_FILE : CONFIRM_DELETE_FILE), (Query));    }    else    {      Query = FMTLOAD((Recycle ? CONFIRM_RECYCLE_FILES : CONFIRM_DELETE_FILES), (FileList->Count));    }    TMessageParams Params(mpNeverAskAgainCheck);    Params.ImageName = L"Delete file";    unsigned int Answer =      MessageDialog(MainInstructions(Query), qtConfirmation, qaOK | qaCancel, HELP_DELETE_FILE, &Params);    if (Answer == qaNeverAskAgain)    {      Result = true;      if (Recycle)      {        WinConfiguration->ConfirmRecycling = false;      }      else      {        WinConfiguration->ConfirmDeleting = false;      }    }    else    {      Result = (Answer == qaOK);    }  }  if (Result)  {    DeleteFiles(Side, FileList, FLAGMASK(Alternative, dfAlternative));  }  return Result;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Operation,  TOperationSide Side, TStrings * FileList, bool NoConfirmation, void * Param){  TAutoBatch AutoBatch(this);  bool Result;  if (TFileOperationProgressType::IsTransferOperation(Operation))  {    Result = ExecuteCopyMoveFileOperation(Operation, Side, FileList, NoConfirmation, Param);  }  else if (Operation == foRename)  {    DebugAssert(DirView(Side)->ItemFocused);    DirView(Side)->ItemFocused->EditCaption();    Result = true;  }  else if (Operation == foDelete)  {    Result = ExecuteDeleteFileOperation(Side, FileList, Param);  }  else if (Operation == foSetProperties)  {    DirView(osRemote)->SaveSelectedNames();    Result = SetProperties(Side, FileList);  }  else if (Operation == foCustomCommand)  {    DebugAssert(Param);    DebugAssert(Side == osRemote); // Side carries no meaning for foCustomCommand    DirView(osRemote)->SaveSelectedNames();    const TCustomCommandType * Command = static_cast<const TCustomCommandType*>(Param);    CustomCommand(FileList, *Command, NULL);    Result = true;  }  else if ((Operation == foRemoteMove) || (Operation == foRemoteCopy))  {    DebugAssert(!IsSideLocalBrowser(Side));    Result = RemoteTransferFiles(FileList, NoConfirmation,      (Operation == foRemoteMove), reinterpret_cast<TManagedTerminal *>(Param));  }  else if (Operation == foLock)  {    DebugAssert(!IsSideLocalBrowser(Side));    LockFiles(FileList, true);    Result = true;  }  else if (Operation == foUnlock)  {    DebugAssert(!IsSideLocalBrowser(Side));    LockFiles(FileList, false);    Result = true;  }  else  {    DebugFail();  }  return Result;}//---------------------------------------------------------------------------TOperationSide __fastcall TCustomScpExplorerForm::GetSide(TOperationSide Side){  if (Side == osCurrent)  {    Side = FCurrentSide;  }  return Side;}//---------------------------------------------------------------------------TOperationSide TCustomScpExplorerForm::GetOtherSide(TOperationSide Side){  TOperationSide Result;  switch (GetSide(Side))  {    case osLocal:      Result = osOther;      break;    case osOther:      Result = osLocal;      break;    default:      DebugFail();      Abort();  }  return Result;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Operation,  TOperationSide Side, bool OnFocused, bool NoConfirmation, void * Param){  Side = GetSide(Side);  bool FullPath = IsSideLocalBrowser(Side);  TCustomDirView * ADirView = DirView(Side);  std::unique_ptr<TStringList> FileList(new TStringList());  ADirView->CreateFileList(OnFocused, FullPath, FileList.get());  bool ReloadProperties =    !IsSideLocalBrowser(Side) && (Operation == foSetProperties) &&    DebugAlwaysTrue(HasActiveTerminal()) && Terminal->IsCapable[fcLoadingAdditionalProperties];  bool Result = ExecuteFileOperation(Operation, Side, FileList.get(), NoConfirmation, Param);  if (Result && ReloadProperties)  {    std::unique_ptr<TStringList> FileList2(new TStringList());    FileList->CaseSensitive = true;    FileList->Sort();    for (int Index = 0; Index < ADirView->Items->Count; Index++)    {      TListItem * Item = ADirView->Items->Item[Index];      UnicodeString FileName = ADirView->ItemFileName(Item);      int Index2;      if (FileList->Find(FileName, Index2))      {        FileList2->AddObject(FileName, ADirView->ItemData(Item));      }    }    LoadFilesProperties(FileList2.get());  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecuteFileOperationCommand(  TFileOperation Operation, TOperationSide Side, bool OnFocused,  bool NoConfirmation, void * Param){  if (ExecuteFileOperation(Operation, Side, OnFocused, NoConfirmation, Param))  {    if (TFileOperationProgressType::IsTransferOperation(Operation))    {      DebugAssert(!IsLocalBrowserMode());      if (GetSide(Side) == osLocal)      {        Configuration->Usage->Inc(L"UploadsCommand");      }      else      {        Configuration->Usage->Inc(L"DownloadsCommand");      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecuteCopyOperationCommand(  TOperationSide Side, bool OnFocused, unsigned int Flags){  TTransferOperationParam Param;  if ((WinConfiguration->Interface != ifCommander) ||      WinConfiguration->ScpCommander.ExplorerKeyboardShortcuts)  {    Flags &= ~cocShortCutHint;  }  TCustomDirView * DView = DirView(Side);  Param.Options =    FLAGMASK(FLAGSET(Flags, cocShortCutHint), coShortCutHint) |    FLAGMASK(SelectedAllFilesInDirView(DView), coAllFiles);  if (FLAGSET(Flags, cocQueue))  {    Param.Queue = asOn;  }  else if (FLAGSET(Flags, cocNonQueue))  {    Param.Queue = asOff;  }  ExecuteFileOperationCommand(foCopy, Side, OnFocused, false, &Param);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::HandleErrorList(TStringList *& ErrorList){  int Count = ErrorList->Count;  try  {    if (ErrorList->Count)    {      UnicodeString Message = MainInstructions(FMTLOAD(ERROR_LIST_COUNT, (ErrorList->Count)));      if (MessageDialog(Message, qtError,          qaOK | qaCancel, HELP_NONE) == qaOK)      {        unsigned int Answer;        int Index = 0;        do        {          DebugAssert(Index >= 0 && Index < Count);          TQueryButtonAlias Aliases[2];          Aliases[0].Button = qaYes;          Aliases[0].Alias = LoadStr(PREV_BUTTON);          Aliases[1].Button = qaNo;          Aliases[1].Alias = LoadStr(NEXT_BUTTON);          TMessageParams Params;          Params.Aliases = Aliases;          Params.AliasesCount = LENOF(Aliases);          int No = Index + 1;          UnicodeString Message = ErrorList->Strings[Index];          UnicodeString AMainInstructions;          UnicodeString Details;          if (ExtractMainInstructions(Message, AMainInstructions))          {            Details = Message;            Message = AMainInstructions;          }          Message = MainInstructions(FMTLOAD(ERROR_LIST_NUMBER, (No, Count, Message))) + Details;          Answer = MoreMessageDialog(            Message,            dynamic_cast<TStrings *>(ErrorList->Objects[Index]), qtError,            (Index ? qaYes : 0) | (Index < Count - 1 ? qaNo : 0) |            qaOK, HELP_NONE, &Params);          if (Answer == qaNo)          {            Index++;          }          if (Answer == qaYes)          {            Index--;          }        }        while (Answer != qaOK);      }    }  }  __finally  {    TStrings * List = ErrorList;    ErrorList = NULL;    for (int i = 0; i < Count; i++)    {      delete List->Objects[i];    }    delete List;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecuteRemoteFile(  const UnicodeString & FullFileName, TRemoteFile * File, TExecuteFileBy ExecuteFileBy){  // needed for checking filemasks, as there's no directory object  // associated with the file object  File->FullFileName = FullFileName;  TFileMasks::TParams MaskParams;  MaskParams.Size = File->Size;  MaskParams.Modification = File->Modification;  ExecuteFile(osRemote, ExecuteFileBy, NULL, FullFileName, File, MaskParams);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::EditNew(TOperationSide Side){  DebugAssert(!WinConfiguration->DisableOpenEdit);  Side = GetSide(Side);  TCustomDirView * DView = DirView(Side);  TListItem * FocusedItem = DView->ItemFocused;  UnicodeString Name;  if ((FocusedItem != NULL) && !DView->ItemIsDirectory(FocusedItem))  {    Name = DView->ItemFileName(FocusedItem);  }  else  {    Name = LoadStr(NEW_FILE);  }  UnicodeString Names = Name;  std::unique_ptr<TStrings> History(CloneStrings(CustomWinConfiguration->History[L"EditFile"]));  if (InputDialog(LoadStr(EDIT_FILE_CAPTION), LoadStr(EDIT_FILE_PROMPT), Names,        HELP_EDIT_NEW, History.get(), true, NULL, true, 400))  {    while (!Names.IsEmpty())    {      Name = CutToChar(Names, FileMasksDelimiters[1], false);      CustomWinConfiguration->History[L"EditFile"] = History.get();      UnicodeString TargetFileName;      UnicodeString LocalFileName;      UnicodeString RootTempDir;      UnicodeString TempDir;      UnicodeString RemoteDirectory;      bool ExistingFile = false;      if (!IsSideLocalBrowser(Side))      {        Name = AbsolutePath(Terminal->CurrentDirectory, Name);        std::unique_ptr<TRemoteFile> File(Terminal->TryReadFile(Name));        if ((File.get() != NULL) &&            !File->IsDirectory)        {          ExecuteRemoteFile(Name, File.get(), efDefaultEditor);          ExistingFile = true;        }        File.reset(NULL);        if (!ExistingFile)        {          RemoteDirectory = UnixExtractFilePath(Name);          TemporaryDirectoryForRemoteFiles(            RemoteDirectory, GUIConfiguration->CurrentCopyParam, false, TempDir, RootTempDir);          TargetFileName = UnixExtractFileName(Name);          TCopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;          LocalFileName = TempDir +            // We probably do not want to trim the VMS version here            Terminal->ChangeFileName(&CopyParam, TargetFileName, osRemote, false);        }      }      else      {        if (ExtractFilePath(Name).IsEmpty())        {          LocalFileName = IncludeTrailingBackslash(DView->PathName) + Name;        }        else        {          LocalFileName = ExpandFileName(Name);        }        TargetFileName = ExtractFileName(Name);      }      if (!ExistingFile)      {        bool NewFile = !FileExists(ApiPath(LocalFileName));        if (NewFile)        {          int File = FileCreate(ApiPath(LocalFileName));          if (File < 0)          {            if (!RootTempDir.IsEmpty())            {              RecursiveDeleteFile(ExcludeTrailingBackslash(RootTempDir));            }            throw Exception(FMTLOAD(CREATE_FILE_ERROR, (LocalFileName)));          }          else          {            FileClose(File);          }        }        TExecuteFileBy ExecuteFileBy = efDefaultEditor;        const TEditorData * ExternalEditor = NULL;        TFileMasks::TParams MaskParams; // size not known        ExecuteFileNormalize(ExecuteFileBy, ExternalEditor, TargetFileName,          false, MaskParams);        CustomExecuteFile(Side, ExecuteFileBy, LocalFileName, TargetFileName,          ExternalEditor, RootTempDir, RemoteDirectory, NewFile, TDateTime());      }    }  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::RemoteExecuteForceText(  TExecuteFileBy ExecuteFileBy, const TEditorData * ExternalEditor){  DebugAssert((ExecuteFileBy == efExternalEditor) ==    ((ExternalEditor != NULL) && (ExternalEditor->Editor == edExternal)));  DebugAssert(ExecuteFileBy != efDefaultEditor);  return    ((ExecuteFileBy == efInternalEditor)) ||    ((ExecuteFileBy == efExternalEditor) && ExternalEditor->ExternalEditorText);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CustomExecuteFile(TOperationSide Side,  TExecuteFileBy ExecuteFileBy, UnicodeString FileName, UnicodeString OriginalFileName,  const TEditorData * ExternalEditor, UnicodeString LocalRootDirectory,  UnicodeString RemoteDirectory, bool NewFile, const TDateTime & SourceTimestamp){  DebugAssert(!WinConfiguration->DisableOpenEdit);  DebugAssert((ExecuteFileBy == efExternalEditor) ==    ((ExternalEditor != NULL) && (ExternalEditor->Editor == edExternal)));  DebugAssert(ExecuteFileBy != efDefaultEditor);  Side = GetSide(Side);  std::unique_ptr<TEditedFileData> Data(new TEditedFileData);  if (!IsSideLocalBrowser(Side))  {    Data->Terminal = Terminal;    Data->SessionData = CloneCurrentSessionData();    Data->ForceText = RemoteExecuteForceText(ExecuteFileBy, ExternalEditor);    Data->RemoteDirectory = RemoteDirectory;    Data->SessionName = Terminal->SessionData->SessionName;    Data->LocalRootDirectory = LocalRootDirectory;    Data->OriginalFileName = OriginalFileName;    Data->Command = L""; // will be changed later for external editor    // Empty SourceTimestamp indicates that checking was disabled when the file was opened    if (WinConfiguration->EditorCheckNotModified)    {      Data->SourceTimestamp = SourceTimestamp;    }  }  if (ExecuteFileBy == efInternalEditor)  {    if (!IsSideLocalBrowser(Side))    {      UnicodeString RemotePath = UnixCombinePaths(RemoteDirectory, OriginalFileName);      UnicodeString Caption = RemotePath + TitleSeparator + Terminal->SessionData->SessionName;      TForm * Editor;      try      {        Editor =          ShowEditorForm(            FileName, this,            FEditorManager->FileChanged, FEditorManager->FileReload, FEditorManager->FileClosed,            SaveAllInternalEditors, AnyInternalEditorModified,            Caption, StandaloneOperation, SessionColor, Terminal->SessionData->InternalEditorEncoding, NewFile);      }      catch(...)      {        if (!LocalRootDirectory.IsEmpty())        {          RecursiveDeleteFile(ExcludeTrailingBackslash(LocalRootDirectory));        }        throw;      }      FEditorManager->AddFileInternal(FileName, Data.release(), Editor);      AppLogFmt(L"Opened internal editor with \"%s\"", (FileName));    }    else    {      DebugAssert(!StandaloneOperation);      TForm * Editor =        ShowEditorForm(FileName, this, NULL, NULL, LocalEditorClosed,          SaveAllInternalEditors, AnyInternalEditorModified,          L"", false, SessionColor, -1, NewFile);      FLocalEditors->Add(Editor);    }  }  else  {    HANDLE Process;    if (ExecuteFileBy == efExternalEditor)    {      UnicodeString Program, Params, Dir;      Data->Command = ExternalEditor->ExternalEditor;      ReformatFileNameCommand(Data->Command);      SplitCommand(Data->Command, Program, Params, Dir);      Params = ExpandFileNameCommand(Params, FileName);      Program = ExpandEnvironmentVariables(Program);      if (!ExecuteShell(Program, Params, Process))      {        throw EOSExtException(FMTLOAD(EDITOR_ERROR, (Program)));      }    }    else    {      DebugAssert(!IsSideLocalBrowser(Side));      if (!ExecuteShell(FileName, L"", Process))      {        throw EOSExtException(FMTLOAD(EXECUTE_FILE_ERROR, (FileName)));      }    }    if (IsSideLocalBrowser(Side) ||        ((ExecuteFileBy == efShell) &&         !WinConfiguration->Editor.SDIShellEditor) ||        ((ExecuteFileBy == efExternalEditor) &&         !ExternalEditor->SDIExternalEditor))    {      // no need for handle      if (Process != NULL)      {        DebugCheck(CloseHandle(Process));      }      Process = INVALID_HANDLE_VALUE;    }    else    {      if (Process == NULL)      {        throw ExtException(LoadStr(OPEN_FILE_NO_PROCESS2), L"", HELP_OPEN_FILE_NO_PROCESS);      }    }    if (!IsSideLocalBrowser(Side))    {      FEditorManager->AddFileExternal(FileName, Data.release(), Process);      AppLogFmt(L"Opened external editor with remote file \"%s\".", (FileName));    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SaveInternalEditor(  const UnicodeString /*FileName*/, TEditedFileData * /*Data*/, TObject * Token,  void * /*Arg*/){  if (Token != NULL)  {    EditorFormFileSave(static_cast<TForm *>(Token));  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SaveAllInternalEditors(TObject * /*Sender*/){  for (int Index = 0; Index < FLocalEditors->Count; Index++)  {    EditorFormFileSave(static_cast<TForm *>(FLocalEditors->Items[Index]));  }  FEditorManager->ProcessFiles(SaveInternalEditor, NULL);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::InternalEditorModified(  const UnicodeString /*FileName*/, TEditedFileData * /*Data*/, TObject * Token,  void * Arg){  if ((Token != NULL) &&      IsEditorFormModified(static_cast<TForm *>(Token)))  {    *static_cast<bool *>(Arg) = true;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AnyInternalEditorModified(  TObject * /*Sender*/, bool & Modified){  for (int Index = 0; !Modified && (Index < FLocalEditors->Count); Index++)  {    if (IsEditorFormModified(static_cast<TForm *>(FLocalEditors->Items[Index])))    {      Modified = true;    }  }  if (!Modified)  {    FEditorManager->ProcessFiles(InternalEditorModified, &Modified);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LocalEditorClosed(TObject * Sender, bool /*Forced*/){  DebugCheck(FLocalEditors->Extract(Sender) >= 0);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TemporaryDirectoryForRemoteFiles(  const UnicodeString & RemoteDirectory, const TCopyParamType & CopyParam, bool Simple,  UnicodeString & Result, UnicodeString & RootDirectory){  if (!WinConfiguration->TemporaryDirectoryDeterministic || Simple)  {    RootDirectory = IncludeTrailingBackslash(WinConfiguration->TemporaryDir());    Result = RootDirectory;  }  else  {    RootDirectory = L"";    Result = WinConfiguration->ExpandedTemporaryDirectory();    Result = IncludeTrailingBackslash(Result);  }  if (WinConfiguration->TemporaryDirectoryAppendSession && !Simple)  {    Result = IncludeTrailingBackslash(Result + MakeValidFileName(Terminal->SessionData->SessionName));  }  if (WinConfiguration->TemporaryDirectoryAppendPath && !Simple)  {    UnicodeString ARemoteDirectory = RemoteDirectory;    if (!ARemoteDirectory.IsEmpty() && (ARemoteDirectory[1] == L'/'))    {      ARemoteDirectory.Delete(1, 1);    }    Result = IncludeTrailingBackslash(Result + CopyParam.ValidLocalPath(FromUnixPath(ARemoteDirectory)));  }  if (!ForceDirectories(ApiPath(Result)))  {    throw EOSExtException(FMTLOAD(CREATE_TEMP_DIR_ERROR, (Result)));  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TemporarilyDownloadFiles(  TStrings * FileList, bool ForceText, UnicodeString & RootTempDir, UnicodeString & TempDir,  bool GetTargetNames, bool AutoOperation, bool SimpleTempDir){  DebugAssert(!IsLocalBrowserMode());  TCopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;  if (ForceText)  {    CopyParam.TransferMode = tmAscii;  }  TemporaryFileCopyParam(CopyParam);  if (TempDir.IsEmpty())  {    TemporaryDirectoryForRemoteFiles(Terminal->CurrentDirectory, CopyParam, SimpleTempDir, TempDir, RootTempDir);  }  DebugAssert(!FAutoOperation);  FAutoOperation = AutoOperation;  FMoveToQueue = false;  Terminal->ExceptionOnFail = true;  try  {    try    {      // turn off confirmations, as for MDI editors we may possibly download      // the same file over      Terminal->CopyToLocal(        FileList, TempDir, &CopyParam, cpNoConfirmation | cpTemporary, NULL);      if (GetTargetNames)      {        for (int i = 0; i < FileList->Count; i++)        {          FileList->Strings[i] =            Terminal->ChangeFileName(&CopyParam, UnixExtractFileName(FileList->Strings[i]), osRemote, false);        }      }    }    catch(...)    {      if (!RootTempDir.IsEmpty())      {        RecursiveDeleteFile(ExcludeTrailingBackslash(RootTempDir));      }      throw;    }  }  __finally  {    FAutoOperation = false;    Terminal->ExceptionOnFail = false;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::EditorAutoConfig(){  // Do not waste time checking for default editor list the next time,  // or testing if default editor is not notepad.  bool TryNextTime = false;  UnicodeString UsageState;  if (!WinConfiguration->EditorList->IsDefaultList())  {    UsageState = "H";  }  else  {    UnicodeString Executable;    UnicodeString ExecutableDescription;    if (DetectSystemExternalEditor(false, Executable, ExecutableDescription, UsageState, TryNextTime))    {      UnicodeString Message =        FMTLOAD(EDITOR_AUTO_CONFIG2, (ExecutableDescription, ExecutableDescription));      unsigned int Answer =        MessageDialog(Message, qtConfirmation, qaOK | qaCancel, HELP_EDITOR_AUTO_CONFIG);      if (Answer != qaOK)      {        UsageState = "R";      }      else      {        UsageState = "A";        TEditorData EditorData;        EditorData.Editor = edExternal;        EditorData.ExternalEditor = FormatCommand(Executable, L"");        EditorData.ExternalEditorOptionsAutodetect();        TEditorList EditorList;        EditorList = *WinConfiguration->EditorList;        EditorList.Insert(0, new TEditorPreferences(EditorData));        WinConfiguration->EditorList = &EditorList;      }    }  }  WinConfiguration->OfferedEditorAutoConfig = !TryNextTime;  WinConfiguration->Usage->Set(L"EditorAutoConfig", UsageState);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecuteFileNormalize(  TExecuteFileBy & ExecuteFileBy, const TEditorData *& ExternalEditor,  const UnicodeString & FileName, bool Local, const TFileMasks::TParams & MaskParams){  if (ExecuteFileBy == efDefaultEditor)  {    if (!WinConfiguration->OfferedEditorAutoConfig)    {      EditorAutoConfig();    }    const TEditorPreferences * Editor =      WinConfiguration->DefaultEditorForFile(FileName, Local, MaskParams);    if ((Editor == NULL) || (Editor->Data->Editor == edInternal))    {      ExecuteFileBy = efInternalEditor;      ExternalEditor = NULL;    }    else if (Editor->Data->Editor == edOpen)    {      ExecuteFileBy = efShell;      ExternalEditor = NULL;    }    else    {      ExecuteFileBy = efExternalEditor;      ExternalEditor = Editor->Data;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecuteFile(TOperationSide Side,  TExecuteFileBy ExecuteFileBy, const TEditorData * ExternalEditor,  UnicodeString FullFileName, TObject * Object, const TFileMasks::TParams & MaskParams){  UnicodeString OriginalFileName;  UnicodeString LocalRootDirectory;  UnicodeString RemoteDirectory;  ExecuteFileNormalize(ExecuteFileBy, ExternalEditor, FullFileName,    IsSideLocalBrowser(Side), MaskParams);  UnicodeString Counter;  UnicodeString LocalFileName;  bool Handled = false;  if (!IsSideLocalBrowser(Side))  {    // We need to trim VMS version here, so that we use name without version    // when uploading back to create a new version of the file    OriginalFileName = Terminal->GetBaseFileName(UnixExtractFileName(FullFileName));    RemoteDirectory = UnixExtractFilePath(FullFileName);    TObject * Token = NULL;    UnicodeString LocalDirectory;    if (!FEditorManager->CanAddFile(RemoteDirectory, OriginalFileName,           Terminal->SessionData->SessionName, Token, LocalRootDirectory,           LocalDirectory))    {      if (Token != NULL)      {        TForm * Form = dynamic_cast<TForm *>(Token);        if (Form->WindowState == wsMinimized)        {          ShowWindow(Form->Handle, SW_RESTORE);        }        else        {          Form->SetFocus();        }        Handled = true;      }      else      {        throw Exception(FMTLOAD(ALREADY_EDITED_EXTERNALLY_OR_UPLOADED, (OriginalFileName)));      }    }    if (!Handled)    {      TStringList * FileList1 = new TStringList();      try      {        FileList1->AddObject(FullFileName, Object);        TemporarilyDownloadFiles(FileList1,          RemoteExecuteForceText(ExecuteFileBy, ExternalEditor),          LocalRootDirectory, LocalDirectory, true, true, false);        LocalFileName = LocalDirectory + FileList1->Strings[0];      }      __finally      {        delete FileList1;      }      switch (ExecuteFileBy)      {        case efShell:          Counter = "RemoteFilesExecuted";          break;        case efInternalEditor:          Counter = "RemoteFilesOpenedInInternalEditor";          break;        case efExternalEditor:          Counter = "RemoteFilesOpenedInExternalEditor";          break;        default:          DebugFail();      }    }  }  else  {    LocalFileName = FullFileName;    OriginalFileName = ExtractFileName(FullFileName);    switch (ExecuteFileBy)    {      case efShell:        Counter = "LocalFilesExecuted";        break;      case efInternalEditor:        Counter = "LocalFilesOpenedInInternalEditor";        break;      case efExternalEditor:        Counter = "LocalFilesOpenedInExternalEditor";        break;      default:        DebugFail();    }  }  if (!Handled)  {    Configuration->Usage->Inc(Counter);    CustomExecuteFile(Side, ExecuteFileBy, LocalFileName, OriginalFileName,      ExternalEditor, LocalRootDirectory, RemoteDirectory, false, MaskParams.Modification);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecuteFile(TOperationSide Side,  TExecuteFileBy ExecuteFileBy, const TEditorData * ExternalEditor,  bool AllSelected, bool OnFocused){  DebugAssert(!WinConfiguration->DisableOpenEdit);  DebugAssert((ExecuteFileBy == efExternalEditor) ==    ((ExternalEditor != NULL) && (ExternalEditor->Editor == edExternal)));  Side = GetSide(Side);  TCustomDirView * DView = DirView(Side);  TStrings * FileList =    AllSelected ?      DView->CreateFileList(OnFocused, IsSideLocalBrowser(Side)) :      DView->CreateFocusedFileList(IsSideLocalBrowser(Side));  try  {    DebugAssert(AllSelected || (FileList->Count == 1));    for (int i = 0; i < FileList->Count; i++)    {      UnicodeString ListFileName = FileList->Strings[i];      UnicodeString FileNameOnly =        !IsSideLocalBrowser(Side) ? UnixExtractFileName(ListFileName) : ExtractFileName(ListFileName);      TListItem * Item = DView->FindFileItem(FileNameOnly);      if (!DView->ItemIsDirectory(Item))      {        UnicodeString FullFileName;        if (!IsSideLocalBrowser(Side))        {          FullFileName = DirView(Side)->Path + ListFileName;        }        else        {          FullFileName = ListFileName;        }        TObject * Object = FileList->Objects[i];        TFileMasks::TParams MaskParams;        MaskParams.Size = DView->ItemFileSize(Item);        TDateTimePrecision Precision;        MaskParams.Modification = DView->ItemFileTime(Item, Precision);        std::unique_ptr<TRemoteFile> File;        if (!IsSideLocalBrowser(Side))        {          File.reset(Terminal->TryReadFile(FullFileName));          if (File.get() != NULL)          {            File->FullFileName = FullFileName;            Object = File.get();            MaskParams.Size = File->Size;            MaskParams.Modification = File->Modification;          }        }        ExecuteFile(Side, ExecuteFileBy, ExternalEditor, FullFileName, Object, MaskParams);      }    }  }  __finally  {    delete FileList;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TemporaryFileCopyParam(TCopyParamType & CopyParam){  CopyParam.FileNameCase = ncNoChange;  CopyParam.PreserveRights = false;  CopyParam.PreserveReadOnly = false;  CopyParam.ReplaceInvalidChars = true;  CopyParam.IncludeFileMask = TFileMasks();  CopyParam.NewerOnly = false;  CopyParam.FileMask = L"";}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::EditorCheckNotModified(const TEditedFileData * Data){  return WinConfiguration->EditorCheckNotModified && (Data->SourceTimestamp != TDateTime());}//---------------------------------------------------------------------------class TEditorUploadQueueItem : public TUploadQueueItem{public:  __fastcall TEditorUploadQueueItem(      TTerminal * Terminal, TStrings * FilesToCopy, const UnicodeString & TargetDir,      const TCopyParamType * CopyParam, int Params) :    TUploadQueueItem(Terminal, FilesToCopy, TargetDir, CopyParam, Params, true, false)  {  }protected:  virtual void __fastcall DoTransferExecute(TTerminal * Terminal, TParallelOperation * ParallelOperation)  {    TUploadQueueItem::DoTransferExecute(Terminal, ParallelOperation);    TTerminalManager::Instance()->ScpExplorer->EditedFileUploaded(Terminal, CompleteEvent);  }};//---------------------------------------------------------------------------void TCustomScpExplorerForm::EditedFileUploaded(TTerminal * ATerminal, HANDLE UploadCompleteEvent){  if (WinConfiguration->EditorCheckNotModified) // optimization  {    UnicodeString RemoteFilePath;    {      TGuard Guard(FEditorManager->Section);      TEditedFileData * Data = FEditorManager->FindByUploadCompleteEvent(UploadCompleteEvent);      if (DebugAlwaysTrue(Data != NULL) &&          EditorCheckNotModified(Data))      {        RemoteFilePath = UnixCombinePaths(Data->RemoteDirectory, Data->OriginalFileName);      }    }    if (!RemoteFilePath.IsEmpty())    {      std::unique_ptr<TRemoteFile> File(ATerminal->TryReadFile(RemoteFilePath));      if (File.get() != NULL)      {        TGuard Guard(FEditorManager->Section);        TEditedFileData * Data = FEditorManager->FindByUploadCompleteEvent(UploadCompleteEvent);        if (DebugAlwaysTrue(Data != NULL))        {          Data->SourceTimestamp = File->Modification;          AppLogFmt(L"Uploaded edited remote file timestamp: %s", (StandardTimestamp(Data->SourceTimestamp)));        }      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecutedFileChanged(  const UnicodeString & FileName, TEditedFileData * Data, HANDLE UploadCompleteEvent, bool & Retry){  TTerminalManager * Manager = TTerminalManager::Instance();  if ((Manager->ActiveTerminal == Data->Terminal) &&      Manager->ScheduleTerminalReconnnect(Data->Terminal))  {    AppLog(L"Scheduled session reconnect, will retry the upload later");    Retry = true;  }  else if (!IsActiveTerminal(Data->Terminal))  {    if (!NonVisualDataModule->Busy)    {      UnicodeString FileNameOnly = ExtractFileName(FileName);      UnicodeString EditInactiveSessionReopenAcceptedCounter = L"EditInactiveSessionReopenAccepted";      UnicodeString EditInactiveSessionReopenRejectedCounter = L"EditInactiveSessionReopenRejected";      if (Data->Terminal == NULL)      {        TManagedTerminal * SameSiteTerminal = Manager->FindActiveTerminalForSite(Data->SessionData);        if (SameSiteTerminal != NULL)        {          UnicodeString Message =            FMTLOAD(EDIT_SESSION_REATTACH,              (FileNameOnly, Data->SessionName, FileNameOnly));          if (MessageDialog(Message, qtConfirmation, qaOK | qaCancel) == qaOK)          {            Data->Terminal = SameSiteTerminal;            Data->SessionName = SameSiteTerminal->SessionData->SessionName;            // We might also overwrite session data            Configuration->Usage->Inc(EditInactiveSessionReopenAcceptedCounter);          }          else          {            Configuration->Usage->Inc(EditInactiveSessionReopenRejectedCounter);            Abort();          }        }      }      // Foreground session should reconnect itself (except for those disconnected explicitly by the user)      else if (DebugAlwaysTrue(Terminal->Disconnected || (Terminal != Data->Terminal)))      {        UnicodeString Message =          MainInstructions(            FMTLOAD(EDIT_SESSION_RECONNECT, (Data->SessionName, FileNameOnly)));        if (MessageDialog(Message, qtConfirmation, qaOK | qaCancel) == qaOK)        {          if (Terminal->Disconnected)          {            Manager->ActiveSession = Terminal;            ReconnectSession();            // Was it reconnected? (if not, Data->Terminal should be nulled now)            if (!IsActiveTerminal(Data->Terminal) || (Terminal != Data->Terminal))            {              Abort();            }          }          else          {            Manager->SetActiveTerminalWithAutoReconnect(Data->Terminal);          }          Configuration->Usage->Inc(EditInactiveSessionReopenAcceptedCounter);        }        else        {          Configuration->Usage->Inc(EditInactiveSessionReopenRejectedCounter);          Abort();        }      }    }    if (!IsActiveTerminal(Data->Terminal))    {      Configuration->Usage->Inc(L"EditInactiveSession");      // Prevent this when not idle (!NonVisualDataModule->Busy)?      throw Exception(FMTLOAD(EDIT_SESSION_CLOSED2,        (ExtractFileName(FileName), Data->SessionName)));    }  }  if (!Retry && EditorCheckNotModified(Data))  {    if (NonVisualDataModule->Busy)    {      Retry = true;    }    else    {      UnicodeString RemoteFilePath = UnixCombinePaths(Data->RemoteDirectory, Data->OriginalFileName);      std::unique_ptr<TRemoteFile> File(Terminal->TryReadFile(RemoteFilePath));      if (File.get() != NULL)      {        AppLogFmt(L"Edited remote file timestamp: %s, Original timestamp: %s", (StandardTimestamp(File->Modification), StandardTimestamp(Data->SourceTimestamp)));        if (File->Modification != Data->SourceTimestamp)        {          UnicodeString Message = MainInstructions(LoadStr(EDIT_CHANGED_EXTERNALLY));          if (MessageDialog(Message, qtConfirmation, qaOK | qaCancel) != qaOK)          {            Abort();          }        }      }    }  }  if (!Retry)  {    TStrings * FileList = new TStringList();    try    {      FileList->Add(FileName);      // Consider using the same settings (preset) as when the file was downloaded.      // More over this does not reflect the actual session that will do the upload.      TGUICopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;      TemporaryFileCopyParam(CopyParam);      if (Data->ForceText)      {        CopyParam.TransferMode = tmAscii;      }      // so i do not need to worry if masking algorithm works in all cases      // ("" means "copy file name", no masking is actually done)      if (ExtractFileName(FileName) == Data->OriginalFileName)      {        CopyParam.FileMask = L"";      }      else      {        CopyParam.FileMask = DelimitFileNameMask(Data->OriginalFileName);      }      int Params = cpNoConfirmation | cpTemporary;      if (Data->Terminal->IsCapable[fcBackgroundTransfers])      {        TTerminalQueue * AQueue = Manager->FindQueueForTerminal(Data->Terminal);        TQueueItem * QueueItem =          new TEditorUploadQueueItem(Data->Terminal, FileList, Data->RemoteDirectory, &CopyParam, Params);        QueueItem->CompleteEvent = UploadCompleteEvent;        AddQueueItem(AQueue, QueueItem, Data->Terminal);      }      else      {        if (NonVisualDataModule->Busy)        {          Retry = true;        }        else        {          FMoveToQueue = false;          Data->Terminal->CopyToRemote(FileList, Data->RemoteDirectory, &CopyParam, Params, NULL);          SetEvent(UploadCompleteEvent);        }      }    }    __finally    {      delete FileList;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecutedFileReload(  const UnicodeString & FileName, TEditedFileData * Data){  // Sanity check, we should not be busy otherwise user would not be able to click Reload button.  DebugAssert(!NonVisualDataModule->Busy);  if (!IsActiveTerminal(Data->Terminal))  {    throw Exception(FMTLOAD(EDIT_SESSION_CLOSED_RELOAD,      (ExtractFileName(FileName), Data->SessionName)));  }  TManagedTerminal * PrevSession = TTerminalManager::Instance()->ActiveSession;  TTerminalManager::Instance()->ActiveSession = Data->Terminal;  NonVisualDataModule->StartBusy();  try  {    std::unique_ptr<TRemoteFile> File;    UnicodeString RemoteFileName =      UnixIncludeTrailingBackslash(Data->RemoteDirectory) + Data->OriginalFileName;    Terminal->ExceptionOnFail = true;    try    {      File.reset(Terminal->ReadFile(RemoteFileName));      if (!File->HaveFullFileName)      {        File->FullFileName = RemoteFileName;      }    }    __finally    {      Terminal->ExceptionOnFail = false;    }    std::unique_ptr<TStrings> FileList(new TStringList());    FileList->AddObject(RemoteFileName, File.get());    UnicodeString RootTempDir = Data->LocalRootDirectory;    UnicodeString TempDir = ExtractFilePath(FileName);    TemporarilyDownloadFiles(FileList.get(), Data->ForceText, RootTempDir, TempDir, true, true, false);    if (EditorCheckNotModified(Data))    {      Data->SourceTimestamp = File->Modification;    }    // sanity check, the target file name should be still the same    DebugAssert(ExtractFileName(FileName) == FileList->Strings[0]);  }  __finally  {    NonVisualDataModule->EndBusy();    // it actually may not exist anymore...    TTerminalManager::Instance()->ActiveSession = PrevSession;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecutedFileEarlyClosed(  const TEditedFileData * Data, bool & KeepOpen){  // Command is set for external editors only (not for "shell" open).  if (!Data->Command.IsEmpty())  {    bool AnyFound = false;    bool AnyMDI = false;    bool AnyNonMDI = false;    bool AnyDetect = false;    TEditorList * EditorList = new TEditorList();    try    {      *EditorList = *WinConfiguration->EditorList;      for (int i = 0; i < EditorList->Count; i++)      {        const TEditorPreferences * Editor = EditorList->Editors[i];        if ((Editor->Data->Editor == edExternal) &&            (Editor->Data->ExternalEditor == Data->Command))        {          AnyFound = true;          if (Editor->Data->SDIExternalEditor)          {            AnyNonMDI = true;            if (Editor->Data->DetectMDIExternalEditor)            {              AnyDetect = true;            }          }          else          {            AnyMDI = true;          }        }      }      bool EnableMDI = false;      bool DisableDetect = false;      if (AnyMDI)      {        KeepOpen = true;        if (AnyNonMDI)        {          // there is at least one instance of the editor with MDI support enabled,          // and one with disabled, enable it for all instances          EnableMDI = true;        }      }      else if (AnyFound && !AnyDetect)      {        // at least once instance found but all have MDI autodetection disabled        // => close the file (default action)      }      else      {        // no instance of the editor has MDI support enabled        TMessageParams Params;        if (AnyFound)        {          // there is at least one instance of the editor          Params.Params |= mpNeverAskAgainCheck;        }        unsigned int Answer = MessageDialog(FMTLOAD(EDITOR_EARLY_CLOSED2, (Data->OriginalFileName)), qtWarning,          qaYes | qaNo, HELP_EDITOR_EARLY_CLOSED, &Params);        switch (Answer)        {          case qaNeverAskAgain:            DisableDetect = true;            break;          case qaNo:            EnableMDI = true;            KeepOpen = true;            break;        }      }      if (AnyFound && (EnableMDI || DisableDetect))      {        bool Changed = false;        for (int i = 0; i < EditorList->Count; i++)        {          const TEditorPreferences * Editor = EditorList->Editors[i];          if ((Editor->Data->Editor == edExternal) &&              (Editor->Data->ExternalEditor == Data->Command) &&              ((EnableMDI && Editor->Data->SDIExternalEditor) ||               (DisableDetect && Editor->Data->DetectMDIExternalEditor)))          {            Changed = true;            TEditorPreferences * UpdatedEditor = new TEditorPreferences(*Editor);            if (EnableMDI)            {              UpdatedEditor->GetData()->SDIExternalEditor = false;            }            if (DisableDetect)            {              UpdatedEditor->GetData()->DetectMDIExternalEditor = false;            }            EditorList->Change(i, UpdatedEditor);          }        }        if (Changed)        {          WinConfiguration->EditorList = EditorList;        }      }    }    __finally    {      delete EditorList;    }  }  else  {    // "open" case    MessageDialog(FMTLOAD(APP_EARLY_CLOSED, (Data->OriginalFileName)), qtWarning,      qaOK, HELP_APP_EARLY_CLOSED);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecutedFileUploadComplete(TObject * Sender){  EditorFormFileUploadComplete(DebugNotNull(dynamic_cast<TForm *>(Sender)));}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteDirViewEnter(TObject * /*Sender*/){  SideEnter(osRemote);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteDriveViewEnter(TObject * /*Sender*/){  MakeNextInTabOrder(RemoteDirPanel, RemoteDrivePanel);  SideEnter(osRemote);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SideEnter(TOperationSide Side){  FCurrentSide = Side;  if (Visible)  {    UpdateControls();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileDeleted(TOperationSide Side, const UnicodeString & FileName, bool Success){  VisualiseOperationFinished(Side, FileName, Success);  if (DebugAlwaysTrue(FDeletedFiles != NULL) && Success)  {    FDeletedFiles->Add(FileName);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DeleteFiles(TOperationSide Side,  TStrings * FileList, bool Alternative){  TCustomDirView * DView = DirView(Side);  DView->SaveSelection();  DView->SaveSelectedNames();  DebugAssert(!FAlternativeDelete);  FAlternativeDelete = Alternative;  try  {    if (!IsSideLocalBrowser(Side))    {      DebugAssert(Terminal != NULL);      // Clone the file list as it may refer to current directory files, which get destroyed, when the directory is reloaded after the operation      std::unique_ptr<TStrings> PermanentFileList(TRemoteFileList::CloneStrings(FileList));      std::unique_ptr<TStringList> DeletedFiles(new TStringList());      DeletedFiles->CaseSensitive = DebugAlwaysTrue(!IsSideLocalBrowser(Side));      int Params = FLAGMASK(Alternative, dfAlternative);      try      {        DebugAssert(FDeletedFiles == NULL);        TValueRestorer<TStrings *> DeletedFilesRestorer(FDeletedFiles, DeletedFiles.get());        TValueRestorer<TFileOperationFinishedEvent> OnFileOperationFinishedRestorer(FOnFileOperationFinished);        FOnFileOperationFinished = FileDeleted;        FMoveToQueue = false;        Terminal->DeleteFiles(FileList, Params);        // Probably not needed for deleting, just for consistency with transfer code        if (FMoveToQueue)        {          Abort();        }      }      catch (EAbort &)      {        if (FMoveToQueue)        {          DeletedFiles->Sorted = true;          for (int Index = 0; Index < PermanentFileList->Count; Index++)          {            if (DeletedFiles->IndexOf(PermanentFileList->Strings[Index]) >= 0)            {              // We should always be deleting the first item => what can be used to optimize this code, if needed              DebugAssert(Index == 0);              PermanentFileList->Delete(Index);              Index--;            }          }          FMoveToQueue = false;          Configuration->Usage->Inc("MovesToBackgroundDelete");          TQueueItem * QueueItem = new TDeleteQueueItem(Terminal, PermanentFileList.get(), Params);          AddQueueItem(Queue, QueueItem, Terminal);          ClearOperationSelection(osRemote);        }      }    }    else    {      if (IsLocalBrowserMode())      {        Configuration->Usage->Inc(L"LocalLocalDeletes");      }      TValueRestorer<TOperationSide> ProgressSideRestorer(FProgressSide, FCurrentSide);      try      {        TTerminalManager::Instance()->LocalTerminal->DeleteLocalFiles(FileList, FLAGMASK(Alternative, dfAlternative));      }      __finally      {        ReloadLocalDirectory();      }    }    FAlternativeDelete = false;  }  catch(...)  {    FAlternativeDelete = false;    DView->DiscardSavedSelection();    throw;  }  DView->RestoreSelection();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LockFiles(TStrings * FileList, bool Lock){  DebugAssert(Terminal);  DebugAssert(!IsLocalBrowserMode());  RemoteDirView->SaveSelection();  RemoteDirView->SaveSelectedNames();  try  {    if (Lock)    {      Terminal->LockFiles(FileList);    }    else    {      Terminal->UnlockFiles(FileList);    }  }  catch(...)  {    RemoteDirView->DiscardSavedSelection();    throw;  }  RemoteDirView->RestoreSelection();}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::DoDirectoryExists(void * Session, const UnicodeString & Directory){  TTerminal * ATerminal = (Session == NULL) ? Terminal : reinterpret_cast<TTerminal *>(Session);  bool Result =    IsActiveTerminal(ATerminal) &&    ATerminal->DirectoryExists(Directory);  return Result;}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::NeedSecondarySessionForRemoteCopy(TStrings * FileList){  bool CopyDirsOnSecondarySession = Terminal->IsCapable[fcSecondaryShell];  return    !Terminal->IsCapable[fcRemoteCopy] ||    (CopyDirsOnSecondarySession && TRemoteFileList::AnyDirectory(FileList));}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::RemoteTransferDialog(TManagedTerminal *& Session,  TStrings * FileList, UnicodeString & Target, UnicodeString & FileMask, bool & DirectCopy,  bool NoConfirmation, bool Move){  DebugAssert(Terminal != NULL);  DebugAssert(Terminal == TTerminalManager::Instance()->ActiveTerminal);  DebugAssert(!IsLocalBrowserMode());  if (Session == NULL)  {    Session = Terminal;  }  bool TargetConfirmed = false;  if (Session == Terminal)  {    if (RemoteDriveView->DropTarget != NULL)    {      Target = RemoteDriveView->NodePathName(RemoteDriveView->DropTarget);      TargetConfirmed = true;    }    else if (RemoteDirView->DropTarget != NULL)    {      DebugAssert(RemoteDirView->ItemIsDirectory(RemoteDirView->DropTarget));      Target = RemoteDirView->ItemFullFileName(RemoteDirView->DropTarget);      TargetConfirmed = true;    }    else    {      Target = RemoteDirView->Path;    }  }  else  {    Target = GetSessionPath(Session, osRemote);  }  Target = UnixIncludeTrailingBackslash(Target);  if (FileList->Count == 1)  {    FileMask = DelimitFileNameMask(UnixExtractFileName(FileList->Strings[0]));  }  else  {    FileMask = AnyMask;  }  DirectCopy = Terminal->IsCapable[fcRemoteCopy] || Terminal->IsCapable[fcSecondaryShell];  bool Result = true;  if (!NoConfirmation)  {    bool Multi = (FileList->Count > 1);    if (Move)    {      Result = DoRemoteMoveDialog(Multi, Target, FileMask, DoDirectoryExists);    }    else    {      std::unique_ptr<TStrings> Sessions(new TStringList);      std::unique_ptr<TStrings> Directories(new TStringList);      TStrings * SessionList = TTerminalManager::Instance()->SessionList;      for (int Index = 0; Index < SessionList->Count; Index++)      {        TManagedTerminal * ASession = DebugNotNull(dynamic_cast<TManagedTerminal *>(SessionList->Objects[Index]));        if (IsActiveTerminal(ASession) && DebugAlwaysTrue(!ASession->LocalBrowser))        {          Sessions->AddObject(SessionList->Strings[Index], ASession);          Directories->Add(GetSessionPath(ASession, osRemote));        }      }      bool AnyDirectory = false;      bool CopyDirsOnSecondarySession = Terminal->IsCapable[fcSecondaryShell];      if (CopyDirsOnSecondarySession && !Terminal->CommandSessionOpened) // optimization      {        for (int Index = 0; !AnyDirectory && (Index < FileList->Count); Index++)        {          AnyDirectory = DebugNotNull(dynamic_cast<TRemoteFile *>(FileList->Objects[Index]))->IsDirectory;        }      }      TDirectRemoteCopy AllowDirectCopy;      if (Terminal->CommandSessionOpened || !NeedSecondarySessionForRemoteCopy(FileList))      {        DebugAssert(DirectCopy);        AllowDirectCopy = drcAllow;      }      else if (Terminal->IsCapable[fcSecondaryShell])      {        DebugAssert(DirectCopy);        AllowDirectCopy = Terminal->IsCapable[fcRemoteCopy] ? drcConfirmCommandSessionDirs : drcConfirmCommandSession;      }      else      {        DebugAssert(!DirectCopy);        AllowDirectCopy = drcDisallow;      }      void * ASession = Session;      Result = DoRemoteCopyDialog(        Sessions.get(), Directories.get(), AllowDirectCopy, Multi, ASession, Target, FileMask, DirectCopy, Terminal,        DoDirectoryExists, TargetConfirmed);      Session = static_cast<TManagedTerminal *>(ASession);    }  }  return Result;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::RemoteTransferFiles(  TStrings * FileList, bool NoConfirmation, bool Move, TManagedTerminal * Session){  DebugAssert(!IsLocalBrowserMode());  bool DirectCopy;  UnicodeString Target, FileMask;  bool Result = RemoteTransferDialog(Session, FileList, Target, FileMask, DirectCopy, NoConfirmation, Move);  if (Result)  {    if (!Move && !DirectCopy)    {      Configuration->Usage->Inc("RemoteCopyTemp");      UnicodeString RootTempDir;      UnicodeString TempDir;      TemporarilyDownloadFiles(FileList, false, RootTempDir, TempDir, false, false, true);      TStrings * TemporaryFilesList = new TStringList();      try      {        TMakeLocalFileListParams MakeFileListParam;        MakeFileListParam.FileList = TemporaryFilesList;        MakeFileListParam.FileTimes = NULL;        MakeFileListParam.IncludeDirs = true;        MakeFileListParam.Recursive = false;        ProcessLocalDirectory(TempDir, Terminal->MakeLocalFileList, &MakeFileListParam);        TTerminalManager::Instance()->ActiveSession = Session;        if (TemporaryFilesList->Count > 0)        {          TGUICopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;          CopyParam.FileMask = FileMask;          DebugAssert(!FAutoOperation);          FAutoOperation = true;          FMoveToQueue = false;          Terminal->CopyToRemote(TemporaryFilesList, Target, &CopyParam, cpTemporary, NULL);        }      }      __finally      {        delete TemporaryFilesList;        FAutoOperation = false;        if (!RootTempDir.IsEmpty())        {          RecursiveDeleteFile(ExcludeTrailingBackslash(RootTempDir));        }      }    }    else    {      RemoteDirView->SaveSelection();      RemoteDirView->SaveSelectedNames();      try      {        if (Move)        {          Configuration->Usage->Inc("RemoteMove");          Terminal->MoveFiles(FileList, Target, FileMask, false);        }        else        {          Configuration->Usage->Inc("RemoteCopyDirect");          DebugAssert(DirectCopy);          DebugAssert(Session == Terminal);          if (!NeedSecondarySessionForRemoteCopy(FileList) ||              Terminal->CommandSessionOpened ||              CommandSessionFallback())          {            Terminal->CopyFiles(FileList, Target, FileMask, false);          }        }      }      catch(...)      {        RemoteDirView->DiscardSavedSelection();        throw;      }      RemoteDirView->RestoreSelection();    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CreateRemoteDirectory(  const UnicodeString & Path, TRemoteProperties & Properties){  DebugAssert(!IsLocalBrowserMode());  Properties.Valid = Properties.Valid << vpEncrypt;  Properties.Encrypt = GUIConfiguration->CurrentCopyParam.EncryptNewFiles;  RemoteDirView->CreateDirectoryEx(Path, &Properties);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CreateDirectory(TOperationSide Side){  Side = GetSide(Side);  TRemoteProperties Properties = GUIConfiguration->NewDirectoryProperties;  TRemoteProperties * AProperties = (!IsSideLocalBrowser(Side) ? &Properties : NULL);  UnicodeString Name = LoadStr(NEW_FOLDER);  int AllowedChanges =    FLAGMASK(!IsSideLocalBrowser(Side) && Terminal->IsCapable[fcModeChanging], cpMode);  bool SaveSettings = false;  if (DoCreateDirectoryDialog(Name, AProperties, AllowedChanges, SaveSettings))  {    TWindowLock Lock(this);    if (!IsSideLocalBrowser(Side))    {      if (SaveSettings)      {        GUIConfiguration->NewDirectoryProperties = Properties;      }      CreateRemoteDirectory(Name, Properties);    }    else    {      DirView(Side)->CreateDirectory(Name);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::HomeDirectory(TOperationSide Side){  TWindowLock Lock(this);  DirView(Side)->ExecuteHomeDirectory();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::OpenDirectory(TOperationSide Side){  DoOpenDirectoryDialog(odBrowse, Side);}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::OpenBookmark(TOperationSide Side, TBookmark * Bookmark){  TOperationSide BookmarkSide = IsLocalBrowserMode() ? osLocal : Side;  UnicodeString Path = Bookmark->GetSideDirectory(BookmarkSide);  bool Result = !Path.IsEmpty();  if (Result)  {    TryOpenDirectory(Side, Path);  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CalculateSize(  TStrings * FileList, __int64 & Size, TCalculateSizeStats & Stats,  bool & Close){  // terminal can be already closed (e.g. dropped connection)  if (Terminal != NULL)  {    try    {      TCalculateSizeParams Params;      Params.Stats = &Stats;      Terminal->CalculateFilesSize(FileList, Size, Params);    }    catch(...)    {      if (!Terminal->Active)      {        Close = true;      }      throw;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CalculateChecksum(const UnicodeString & Alg,  TStrings * FileList, TCalculatedChecksumEvent OnCalculatedChecksum,  bool & Close){  if ((Terminal != NULL) && // terminal can be already closed (e.g. dropped connection)      EnsureCommandSessionFallback(fcCalculatingChecksum))  {    Configuration->Usage->Inc(L"ChecksumCalculated");    try    {      Terminal->CalculateFilesChecksum(Alg, FileList, OnCalculatedChecksum);    }    catch(...)    {      if (!Terminal->Active)      {        Close = true;      }      throw;    }  }}//---------------------------------------------------------------------------void TCustomScpExplorerForm::LoadFilesProperties(TStrings * FileList){  if (Terminal->LoadFilesProperties(FileList))  {    RemoteDirView->Invalidate();  }}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::CanCalculateChecksum(){  return    Terminal->IsCapable[fcCalculatingChecksum] ||    (Terminal->IsCapable[fcSecondaryShell] && !Terminal->IsEncryptingFiles());}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::SetProperties(TOperationSide Side, TStrings * FileList){  bool Result;  if (!IsSideLocalBrowser(Side))  {    TRemoteTokenList * GroupList = NULL;    TRemoteTokenList * UserList = NULL;    try    {      TRemoteProperties CurrentProperties;      LoadFilesProperties(FileList);      bool CapableGroupChanging = Terminal->IsCapable[fcGroupChanging];      bool CapableOwnerChanging = Terminal->IsCapable[fcOwnerChanging];      if (CapableGroupChanging || CapableOwnerChanging)      {        if (CapableGroupChanging)        {          GroupList = Terminal->Groups->Duplicate();        }        if (CapableOwnerChanging)        {          UserList = Terminal->Users->Duplicate();        }        TRemoteDirectory * Files = Terminal->Files;        int Count = Files->Count;        if (Count > 100)        {          Count = 100;        }        for (int Index = 0; Index < Count; Index++)        {          TRemoteFile * File = Files->Files[Index];          if (CapableGroupChanging)          {            GroupList->AddUnique(File->Group);          }          if (CapableOwnerChanging)          {            UserList->AddUnique(File->Owner);          }        }        // if we haven't collected tokens for all files in current directory,        // make sure we collect them at least for all selected files.        // (note that so far the files in FileList has to be from current direcotry)        if (Count < Files->Count)        {          for (int Index = 0; Index < FileList->Count; Index++)          {            TRemoteFile * File = (TRemoteFile *)(FileList->Objects[Index]);            if (CapableGroupChanging)            {              GroupList->AddUnique(File->Group);            }            if (CapableOwnerChanging)            {              UserList->AddUnique(File->Owner);            }          }        }      }      CurrentProperties = TRemoteProperties::CommonProperties(FileList);      bool CapableAclChanging = Terminal->IsCapable[fcAclChangingFiles];      if (CapableAclChanging && TRemoteFileList::AnyDirectory(FileList))      {        CapableAclChanging = false;        CurrentProperties.Valid = CurrentProperties.Valid >> vpRights;      }      int Flags = 0;      if (Terminal->IsCapable[fcModeChanging]) Flags |= cpMode;      if (CapableAclChanging) Flags |= cpAcl;      if (CapableOwnerChanging) Flags |= cpOwner;      if (CapableGroupChanging) Flags |= cpGroup;      TCalculateChecksumEvent CalculateChecksumEvent = NULL;      if (CanCalculateChecksum())      {        CalculateChecksumEvent = CalculateChecksum;      }      std::unique_ptr<TStrings> ChecksumAlgs(new TStringList());      Terminal->GetSupportedChecksumAlgs(ChecksumAlgs.get());      TRemoteProperties NewProperties = CurrentProperties;      Result =        DoPropertiesDialog(FileList, RemoteDirView->PathName,          GroupList, UserList, ChecksumAlgs.get(), &NewProperties, Flags,          Terminal->IsCapable[fcGroupOwnerChangingByID],          CalculateSize, CalculateChecksumEvent);      if (Result)      {        NewProperties = TRemoteProperties::ChangedProperties(CurrentProperties, NewProperties);        Terminal->ChangeFilesProperties(FileList, &NewProperties);      }    }    __finally    {      delete GroupList;      delete UserList;    }  }  else  {    DirView(Side)->DisplayPropertiesMenu();    Result = true;  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::KeyProcessed(Word & Key, TShiftState Shift){  if (Shift * AllKeyShiftStates() == (TShiftState() << ssAlt))  {    FIgnoreNextDialogChar = Key;  }  Key = 0;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CheckCustomCommandShortCut(  TCustomCommandList * List, Word & Key, Classes::TShiftState Shift, TShortCut KeyShortCut){  const TCustomCommandType * Command = List->Find(KeyShortCut);  if (Command != NULL)  {    KeyProcessed(Key, Shift);    if (CustomCommandState(*Command, false, ccltAll) > 0)    {      TAutoFlag DontCopyCommandToClipboardFlag(DontCopyCommandToClipboard);      ExecuteFileOperationCommand(foCustomCommand, osRemote,        false, false, const_cast<TCustomCommandType *>(Command));    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::KeyDown(Word & Key, Classes::TShiftState Shift){  if (!NonVisualDataModule->Busy)  {    if (QueueView3->Focused() && (QueueView3->OnKeyDown != NULL))    {      QueueView3->OnKeyDown(QueueView3, Key, Shift);    }    if ((Key != 0) && !DirView(osCurrent)->IsEditing())    {      TShortCut KeyShortCut = ShortCut(Key, Shift);      for (int Index = 0; Index < NonVisualDataModule->ExplorerActions->ActionCount; Index++)      {        // Note that handling shortcuts on panel (current control) popup menu has precendence over this.        // But so far it's not a problem, as it does what we want.        TAction * Action = (TAction *)NonVisualDataModule->ExplorerActions->Actions[Index];        if (((Action->ShortCut == KeyShortCut) ||             (Action->SecondaryShortCuts->IndexOfShortCut(KeyShortCut) >= 0)) &&            AllowedAction(Action, aaShortCut))        {          // Has to be called before the action as the dialog char is already in queue.          // So when the action consumes message queue, we already need to have the          // FIgnoreNextDialogChar set          KeyProcessed(Key, Shift);          // Reset reference to previous component (when menu/toolbar was clicked).          // Needed to detect that action was invoked by keyboard shortcut          // in TNonVisualDataModule::ExplorerActionsExecute          Action->ActionComponent = NULL;          Action->Execute();          return;        }      }      for (int i = 0; i < TTerminalManager::Instance()->Count; i++)      {        if (NonVisualDataModule->OpenSessionShortCut(i) == KeyShortCut)        {          KeyProcessed(Key, Shift);          TTerminalManager::Instance()->ActiveSessionIndex = i;          return;        }      }      if (Key == VK_TAB && Shift.Contains(ssCtrl))      {        KeyProcessed(Key, Shift);        TTerminalManager::Instance()->CycleTerminals(!Shift.Contains(ssShift));      }      TShortCut CustomShortCut = NormalizeCustomShortCut(KeyShortCut);      if (IsCustomShortCut(CustomShortCut))      {        CheckCustomCommandShortCut(WinConfiguration->CustomCommandList, Key, Shift, CustomShortCut);        CheckCustomCommandShortCut(WinConfiguration->ExtensionList, Key, Shift, CustomShortCut);        if (WinConfiguration->SharedBookmarks != NULL)        {          TBookmark * Bookmark = WinConfiguration->SharedBookmarks->FindByShortCut(CustomShortCut);          if ((Bookmark != NULL) &&              OpenBookmark(FCurrentSide, Bookmark))          {            KeyProcessed(Key, Shift);          }        }      }    }  }  TForm::KeyDown(Key, Shift);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::InitStatusBar(){  bool OpenedTerminal = false;  UnicodeString ProtocolName;  UnicodeString ProtocolNameHint;  UnicodeString SecurityProtocolName;  UnicodeString DurationHint;  // See the comment in TScpCommanderForm::UpdateControls()  TTerminal * ActiveTerminal = TTerminalManager::Instance()->ActiveTerminal;  if (ActiveTerminal != NULL)  {    // Active is not enough here    if (ActiveTerminal->Status == ssOpened)    {      const TSessionInfo & SessionInfo = ActiveTerminal->GetSessionInfo();      const TFileSystemInfo & FileSystemInfo = ActiveTerminal->GetFileSystemInfo();      if (FileSystemInfo.ProtocolName.IsEmpty())      {        ProtocolName = SessionInfo.ProtocolName;      }      else      {        ProtocolName = FileSystemInfo.ProtocolName;      }      ProtocolNameHint = LoadStr(STATUS_PROTOCOL_HINT);      SecurityProtocolName = SessionInfo.SecurityProtocolName;      DurationHint = LoadStr(STATUS_DURATION_HINT);      OpenedTerminal = true;    }    else if (ActiveTerminal->Status > ssClosed)    {      ProtocolName = LoadStr(STATUS_CONNECTING);    }    else    {      ProtocolName = LoadStr(STATUS_NOT_CONNECTED2);    }  }  TTBXStatusBar * SessionStatusBar = (TTBXStatusBar *)GetComponent(fcStatusBar);  int Offset = SessionStatusBar->Panels->Count - SessionPanelCount;  TTBXStatusPanel * ProtocolStatusPanel = SessionStatusBar->Panels->Items[Offset + 0];  ProtocolStatusPanel->ViewPriority = (ActiveTerminal != NULL) ? 100 : 0;  if (ProtocolStatusPanel->Caption != ProtocolName)  {    ProtocolStatusPanel->Caption = ProtocolName;    std::unique_ptr<TCanvas> Canvas(CreateControlCanvas(SessionStatusBar));    ProtocolStatusPanel->Size = Canvas->TextWidth(ProtocolName) + ScaleByTextHeight(SessionStatusBar, 32);  }  ProtocolStatusPanel->Hint = ProtocolNameHint;  TTBXStatusPanel * SecurityStatusPanel = SessionStatusBar->Panels->Items[Offset + 1];  SecurityStatusPanel->ViewPriority = OpenedTerminal ? 98 : 0;  bool SecurityEnabled = !SecurityProtocolName.IsEmpty();  SecurityStatusPanel->Enabled = SecurityEnabled;  UnicodeString SecurityProtocolHint;  if (SecurityEnabled)  {    SecurityProtocolHint = FMTLOAD(STATUS_SECURE, (SecurityProtocolName));  }  else  {    SecurityProtocolHint = LoadStr(STATUS_INSECURE);  }  SecurityStatusPanel->Hint = SecurityProtocolHint;  TTBXStatusPanel * DurationStatusPanel = SessionStatusBar->Panels->Items[Offset + 2];  DurationStatusPanel->ViewPriority = OpenedTerminal ? 99 : 0;  DurationStatusPanel->Hint = DurationHint;  UpdateStatusBar();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateStatusBar(){  TTBXStatusBar * SessionStatusBar = (TTBXStatusBar *)GetComponent(fcStatusBar);  DebugAssert(SessionStatusBar != NULL);  TTBXStatusPanel * NoteStatusPanel = SessionStatusBar->Panels->Items[0];  if (!FNote.IsEmpty())  {    NoteStatusPanel->Caption = FNote;  }  else  {    UpdateStatusPanelText(NoteStatusPanel);  }  NoteStatusPanel->Hint = FNoteHints;  UnicodeString LoginTime;  // See the comment in TScpCommanderForm::UpdateControls()  TTerminal * ActiveTerminal = TTerminalManager::Instance()->ActiveTerminal;  // Active is not enough here  if ((ActiveTerminal != NULL) && (ActiveTerminal->Status == ssOpened))  {    const TSessionInfo & SessionInfo = ActiveTerminal->GetSessionInfo();    LoginTime = FormatDateTimeSpan(Now() - SessionInfo.LoginTime);  }  TTBXStatusPanel * DurationStatusPanel = SessionStatusBar->Panels->Items[SessionStatusBar->Panels->Count - 1];  DurationStatusPanel->Caption = LoginTime;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateStatusPanelText(TTBXStatusPanel * Panel){  Panel->Caption = L"";}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::Idle(){  if (FShowing ||      // Particularly for      // - Standalone editing      // - Detecting closed connection and automatically reconnect it while waiting for changes      //   while "keeping remote directory up to date".      StandaloneOperation)  {    FEditorManager->Check();    // make sure that Idle is called before update queue, as it may invoke QueueEvent    // that needs to know if queue view is visible (and it may be closed after queue update)    TTerminalManager::Instance()->Idle(FDoNotIdleCurrentTerminal > 0);  }  if (FShowing)  {    if (!NonVisualDataModule->Busy &&        // Menu is opened or drag&drop is going on        (Mouse->Capture == NULL))    {      if (FRefreshRemoteDirectory)      {        if ((Terminal != NULL) && (Terminal->Status == ssOpened))        {          Terminal->RefreshDirectory();        }        FRefreshRemoteDirectory = false;      }      if (FRefreshLocalDirectory)      {        ReloadLocalDirectory();        FRefreshLocalDirectory = false;      }      if (WinConfiguration->RefreshRemotePanel)      {        if ((Terminal != NULL) && (Terminal->Status == ssOpened) &&            (Now() - Terminal->DirectoryLoaded > WinConfiguration->RefreshRemotePanelInterval))        {          RemoteDirView->ReloadDirectory();        }      }    }    // TB2 shows accels on Alt key down, but hides it only after menu modal loop finishes.    // But if Alt is used to switch apps or for keyboard shortcut, the menu modal loop does not happen and accelerators stay displayed.    // It's difficult to fix this in TB2, as there's no "up" equivalent to CM_DIALOGKEY, which shows the accels.    // And the Alt key can be released even when other window or application is active, so handling the key up in explorer window won't do either.    TTBCustomToolbar * MenuToolbar = DebugNotNull(dynamic_cast<TTBCustomToolbar *>(GetComponent(fcMenu)));    MenuToolbar->Idle();  }  if (FShowing || StandaloneOperation)  {    if (FQueueStatusInvalidated)    {      UpdateQueueStatus(false);    }    RefreshQueueItems();  }  if (FShowing)  {    UpdateStatusBar();  }  if (FClipboardFakeMonitorsPendingReset && !FDownloadingFromClipboard)  {    FClipboardFakeMonitorsPendingReset = false;    FClipboardFakeMonitors.reset(NULL);  }  FIgnoreNextDialogChar = 0;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UserActionTimer(TObject * /*Sender*/){  try  {    FUserActionTimer->Enabled = false;    if (IsQueueAutoPopup() && (FPendingQueueActionItem != NULL))    {      if (TQueueItem::IsUserActionStatus(FPendingQueueActionItem->Status))      {        FPendingQueueActionItem->ProcessUserAction();      }    }  }  __finally  {    FPendingQueueActionItem = NULL;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ApplicationMinimize(TObject * /*Sender*/){  if (WinConfiguration->MinimizeToTray)  {    UpdateTrayIcon();    FTrayIcon->Visible = true;    if (Visible)    {      ShowWindow(Handle, SW_HIDE);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ApplicationRestore(TObject * /*Sender*/){  // WORKAROUND  // When restoring maximized window from minimization,  // rarely some controls do not align properly.  // Two instances seen (both for Commander):  // - When restoring, window is temporarily narrower (not maximized),  //   causing toolbars on TopDock to wrap and dock to expand horizontally.  //   Once maximized already, top dock shinks back, but the session PageControl,  //   do not align up, leaving space between TopDock and PageControl.  // - Similar issue seen with LocalDirView not aligning down to status bar.  for (int Index = 0; Index < ControlCount; Index++)  {    RealignControl(Controls[Index]);  }  if (FTrayIcon->Visible)  {    FTrayIcon->Visible = false;    if (Visible)    {      ShowWindow(Handle, SW_SHOW);    }  }  if (FNeedSession && DebugAlwaysTrue(Terminal == NULL))  {    FNeedSession = false;    NonVisualDataModule->StartBusy();    try    {      NeedSession(true);    }    __finally    {      NonVisualDataModule->EndBusy();    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateTrayIcon(){  FTrayIcon->Hint = GetMainForm()->Caption;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ApplicationTitleChanged(){  UpdateTrayIcon();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RestoreApp(){  // workaround  // TApplication.WndProc sets TApplication.FAppIconic to false,  // on WM_ACTIVATEAPP, what renders TApplication.Restore no-op function.  // But WM_ACTIVATEAPP message can be received even when  // the main window is minimized to the tray and internal editor window is focused  // (after another application was previously active)  if (::IsIconic(Handle))  {    if (!IsAppIconic())    {      SetAppIconic(true);    }  }  ::ApplicationRestore();  Application->BringToFront();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TrayIconClick(TObject * /*Sender*/){  RestoreApp();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::NewSession(const UnicodeString & SessionUrl){  if (OpenInNewWindow())  {    ExecuteNewInstance(SessionUrl);  }  else  {    TTerminalManager::Instance()->NewSession(SessionUrl);  }}//---------------------------------------------------------------------------void TCustomScpExplorerForm::NewTab(TOperationSide, bool){  NewSession();}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::SaveHiddenDuplicateSession(TSessionData * SessionData){  UnicodeString SessionName = StoredSessions->HiddenPrefix + ManagedSession->SessionData->SessionName;  StoredSessions->NewSession(SessionName, SessionData);  // modified only, explicit  StoredSessions->Save(false, true);  // encode session name because of slashes in hierarchical sessions  return EncodeUrlString(SessionName);}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::CreateHiddenDuplicateSession(){  // current working directories become defaults here, what is not right  std::unique_ptr<TSessionData> SessionData(CloneCurrentSessionData());  return SaveHiddenDuplicateSession(SessionData.get());}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DuplicateTab(){  if (OpenInNewWindow())  {    ExecuteNewInstance(CreateHiddenDuplicateSession());  }  else  {    // current working directories become defaults here, what is not right    std::unique_ptr<TSessionData> SessionData(CloneCurrentSessionData());    TTerminalManager * Manager = TTerminalManager::Instance();    TManagedTerminal * ASession = Manager->NewManagedTerminal(SessionData.get());    DebugAssert(ASession->LocalBrowser == ManagedSession->LocalBrowser);    // We definitely want these    ASession->Disconnected = ManagedSession->Disconnected;    // Not sure about these two    ASession->Permanent = ManagedSession->Permanent;    ASession->DisconnectedTemporarily = ManagedSession->DisconnectedTemporarily;    Manager->ActiveSession = ASession;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RenameTab(){  UnicodeString Name = ManagedSession->SessionData->SessionName;  if (InputDialog(LoadStr(RENAME_TAB_TITLE), LoadStr(RENAME_TAB_PROMPT), Name, HELP_TAB_RENAME) &&      // When submitting the default name, do not fix it      (Name != ManagedSession->SessionData->SessionName))  {    // Checks for a slash only, so it's not that big deal that we do the check after submitting the dialog only.    TSessionData::ValidateName(Name);    // This is inconsistent with how color (for example) is handled.    ManagedSession->SessionData->Name = Name;    UpdateControls();    // Add/Remove distinguishing paths from sessions of the same name.    SessionListChanged();  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanCloseQueue(TTerminalQueue * Queue){  DebugAssert(Queue != NULL);  bool Result = Queue->IsEmpty;  if (!Result)  {    SetFocus();    Result = (MessageDialog(LoadStr(PENDING_QUEUE_ITEMS2), qtWarning, qaOK | qaCancel, HELP_NONE) == qaOK);  }  return Result;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanCloseQueue(){  return CanCloseQueue(FQueue);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CloseTab(){  if (CanCloseQueue())  {    TTerminalManager::Instance()->FreeActiveTerminal();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DisconnectSession(){  if (CanCloseQueue())  {    TTerminalManager::Instance()->DisconnectActiveTerminal();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TerminalDisconnected(){  DetachTerminal(Terminal);  RemoteDirView->Terminal = Terminal;  UpdateRemotePathComboBox(false);  InitStatusBar();  UpdateControls();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TerminalConnecting(){  InitStatusBar();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ReconnectSession(){  if (DebugAlwaysTrue(!Terminal->Active))  {    TTerminalManager::Instance()->ReconnectActiveTerminal();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::OpenStoredSession(TSessionData * Data){  if (OpenInNewWindow())  {    // encode session name because of slashes in hierarchical sessions    ExecuteNewInstance(EncodeUrlString(Data->Name));  }  else  {    TTerminalManager * Manager = TTerminalManager::Instance();    TManagedTerminal * Terminal = Manager->NewManagedTerminal(Data);    Manager->ActiveSession = Terminal;  }}//---------------------------------------------------------------------------void TCustomScpExplorerForm::DoOpenFolderOrWorkspace(  const UnicodeString & Name, bool ConnectFirstTerminal, bool CheckMaxSessions){  TTerminalManager * Manager = TTerminalManager::Instance();  std::unique_ptr<TObjectList> DataList(new TObjectList());  // This asks for a master password. Maybe we should postpone asking until a connection is actually opened.  StoredSessions->GetFolderOrWorkspace(Name, DataList.get());  if (!CheckMaxSessions || (DataList->Count <= WinConfiguration->MaxSessions))  {    TManagedTerminal * FirstSession = Manager->NewSessions(DataList.get());    // FirstSession can be null, if none of the workspace sites exist anymore    // or if all workspace sessions are not suported by the interface    // (when trying to open all local-local workspace in "explorer" interface)    if (FirstSession != NULL)    {      if (!ConnectFirstTerminal)      {        FirstSession->Disconnected = true;        FirstSession->DisconnectedTemporarily = true;      }      Manager->ActiveSession = FirstSession;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::OpenFolderOrWorkspace(const UnicodeString & Name){  if (OpenInNewWindow())  {    ExecuteNewInstance(Name);  }  else  {    DoOpenFolderOrWorkspace(Name, true, false);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FormCloseQuery(TObject * /*Sender*/,      bool &CanClose){  AppLog(L"Windows close query");  // See the comment in CloseApp()  if (NonVisualDataModule->Busy)  {    CanClose = false;  }  else  {    TTerminalManager * Manager = TTerminalManager::Instance();    int ActiveSessions = 0;    for (int Index = 0; Index < Manager->Count; Index++)    {      if (Manager->Sessions[Index]->Active)      {        ActiveSessions++;      }    }    // Confirm, when there's at least one active remote session or    // when there are multiple (inactive or local) sessions and auto workspace saving is not enabled.    if (((ActiveSessions > 0) || ((Manager->Count > 1) && !WinConfiguration->AutoSaveWorkspace)) &&        WinConfiguration->ConfirmClosingSession)    {      unsigned int Result;      TMessageParams Params(mpNeverAskAgainCheck);      UnicodeString Message;      int Answers = qaOK | qaCancel;      // The current session is the only active session      if ((ActiveSessions == 1) && (Terminal != NULL) && Terminal->Active)      {        if (!WinConfiguration->AutoSaveWorkspace)        {          Message = LoadStr(CLOSE_SESSION_WORKSPACE);        }        else        {          Message = LoadStr(CLOSE_SESSION);        }        Message = FORMAT(Message, (Terminal->SessionData->SessionName));      }      // Multiple active sessions or one active session, but it's not the current one      else if (ActiveSessions > 0)      {        if (!WinConfiguration->AutoSaveWorkspace)        {          Message = LoadStr(CLOSE_SESSIONS_WORKSPACE3);        }        else        {          Message = LoadStr(CLOSE_SESSIONS);        }      }      // Multiple tabs, but all are inactive or local, and saving of worspace is not enabled      else      {        DebugAlwaysTrue(Manager->Count > 1);        DebugAlwaysTrue(!WinConfiguration->AutoSaveWorkspace);        Message = LoadStr(CLOSE_WORKSPACE);      }      UnicodeString Note;      if (WinConfiguration->AutoSaveWorkspace)      {        Note = FMTLOAD(AUTO_WORKSPACE, (WorkspaceName()));      }      else      {        Note = LoadStr(AUTO_WORKSPACE_ENABLE);        Answers = qaYes | qaNo | qaCancel;      }      Message = FORMAT("%s\n\n%s", (MainInstructions(Message), Note));      SetFocus();      Result = MessageDialog(Message, qtConfirmation,        Answers, HELP_CLOSE_SESSION_WORKSPACE, &Params);      if (Result == qaNeverAskAgain)      {        WinConfiguration->ConfirmClosingSession = false;      }      if (Result == qaNo)      {        CanClose = SaveWorkspace(true);        // note that the workspace will be saved redundatly again from FormClose      }      else      {        CanClose =          (Result == qaOK) ||          (Result == qaYes) || // CLOSE_SESSIONS_WORKSPACE variant          (Result == qaNeverAskAgain);      }    }    if (CanClose && HasActiveTerminal())    {      CanClose = CanCloseQueue();    }  }  if (CanClose)  {    CanClose =      FEditorManager->CloseInternalEditors(CloseInternalEditor) &&      FEditorManager->CloseExternalFilesWithoutProcess();    if (CanClose)    {      while (CanClose && (FLocalEditors->Count > 0))      {        int PrevCount = FLocalEditors->Count;        static_cast<TForm *>(FLocalEditors->Items[0])->Close();        CanClose = (FLocalEditors->Count < PrevCount);      }      if (CanClose)      {        CanClose = FEditorManager->Empty(true);        if (!CanClose)        {          SetFocus();          CanClose =            (MessageDialog(              LoadStr(PENDING_EDITORS), qtWarning, qaIgnore | qaCancel, HELP_NONE) == qaIgnore);        }      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CloseInternalEditor(TObject * Sender){  TForm * Form = dynamic_cast<TForm *>(Sender);  DebugAssert(Form != NULL);  Form->Close();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ForceCloseInternalEditor(TObject * Sender){  TForm * Form = dynamic_cast<TForm *>(Sender);  delete Form;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ForceCloseLocalEditors(){  while (FLocalEditors->Count > 0)  {    delete static_cast<TForm *>(FLocalEditors->Items[0]);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteDirViewDisplayProperties(      TObject *Sender){  TStrings *FileList = ((TUnixDirView*)Sender)->CreateFileList(True, False, NULL);  try  {    SetProperties(osRemote, FileList);  }  __finally  {    delete FileList;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ComponentShowing(Byte Component, bool value){  if (value)  {    if (Component == fcCustomCommandsBand)    {      UpdateCustomCommandsToolbar();    }    if (Component == fcQueueFileList)    {      DebugAssert(!QueueFileListSplitter->Visible);      AdjustQueueLayout();      UpdateQueueFileList();    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AdjustQueueLayout(){  int MinHeightLimit =    GetStaticQueuePanelComponentsHeight() +    QueueFileListSplitter->Height +    QueueFileList->Height +    GetMinQueueViewHeight();  if (QueuePanel->ClientHeight < MinHeightLimit)  {    QueuePanel->ClientHeight = MinHeightLimit;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetComponentVisible(Byte Component, Boolean value){  TControl * Control = GetComponent(Component);  DebugAssert(Control);  bool Changed = (Control->Visible != value);  if (Changed)  {    ComponentShowing(Component, value);    TWinControl * WinControl = dynamic_cast<TWinControl*>(Control);    bool WasFocused = (WinControl != NULL) && (ActiveControl != NULL) &&      ((ActiveControl == WinControl) || (ActiveControl->Parent == WinControl));    if (value)    {      int RemainingHeight = Control->Parent->ClientHeight;      int RemainingWidth = Control->Parent->ClientWidth;      for (int i = 0; i < Control->Parent->ControlCount; i++)      {        TControl * ChildControl = Control->Parent->Controls[i];        if (ChildControl->Visible)        {          switch (ChildControl->Align)          {            case alTop:            case alBottom:              RemainingHeight -= ChildControl->Height;              break;            case alLeft:            case alRight:              RemainingWidth -= ChildControl->Width;              break;          }        }      }      int Reserve = ScaleByTextHeight(this, 32);      // queue in explorer, trees in commander      if (Control->Height > RemainingHeight - Reserve)      {        Control->Height = RemainingHeight / 2;      }      if (Control->Width > RemainingWidth - Reserve)      {        Control->Width = RemainingWidth / 2;      }    }    Control->Visible = value;    if (WasFocused && Visible)    {      DirView(osCurrent)->SetFocus();    }    FixControlsPlacement();  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::GetComponentVisible(Byte Component){  TControl * Control = GetComponent(Component);  if (Control == NULL)  {    return false;  }  else  {    return Control->Visible;  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::IsComponentPossible(Byte Component){  bool Result;  if ((Component == fcExplorerUpdatesBand) || (Component == fcCommanderUpdatesBand))  {    Result = !IsUWP();  }  else  {    Result = true;  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::MakeFocusedItemVisible(TCustomDirView * DirView){  if (DirView->ItemFocused != NULL)  {    DirView->ItemFocused->MakeVisible(false);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FixControlsPlacement(){  MakeFocusedItemVisible(RemoteDirView);  QueueSplitter->Visible = QueuePanel->Visible;  QueueFileListSplitter->Visible = QueueFileList->Visible;  RemotePanelSplitter->Visible = RemoteDrivePanel->Visible;  TControl * TopControlsOrder[] =    { TopDock, MessageDock, SessionsPageControl };  SetVerticalControlsOrder(TopControlsOrder, LENOF(TopControlsOrder));  TControl * QueueControlsOrder[] =    { QueueDock, QueueView3, QueueFileListSplitter, QueueFileList };  SetVerticalControlsOrder(QueueControlsOrder, LENOF(QueueControlsOrder));}//---------------------------------------------------------------------------TControl * __fastcall TCustomScpExplorerForm::GetComponent(Byte Component){  switch (Component) {    case fcStatusBar: return RemoteStatusBar;    case fcRemotePopup: return reinterpret_cast<TControl *>(NonVisualDataModule->RemoteFilePopup);    case fcQueueView: return QueuePanel;    case fcQueueToolbar: return QueueDock;    case fcRemoteTree: return RemoteDrivePanel;    case fcSessionsTabs: return SessionsPageControl;    case fcQueueFileList: return QueueFileList;    default: return NULL;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewColumnRightClick(      TObject *Sender, TListColumn *Column, TPoint &Point){  DebugAssert(NonVisualDataModule && Column && Sender);  NonVisualDataModule->ListColumn = Column;  TPopupMenu * DirViewColumnMenu;  if (Sender == DirView(osOther))  {    DirViewColumnMenu = NonVisualDataModule->RemoteDirViewColumnPopup;    NonVisualDataModule->RemoteSortByExtColumnPopupItem->Visible = (Column->Index == uvName);    bool SizeColumn = (Column->Index == uvSize);    NonVisualDataModule->RemoteFormatSizeBytesPopupItem->Visible = SizeColumn;    NonVisualDataModule->RemoteCalculateDirectorySizesPopupItem->Visible = SizeColumn;  }  else  {    DirViewColumnMenu = NonVisualDataModule->LocalDirViewColumnPopup;    NonVisualDataModule->LocalSortByExtColumnPopupItem->Visible = (Column->Index == dvName);    bool SizeColumn = (Column->Index == dvSize);    NonVisualDataModule->LocalFormatSizeBytesPopupItem->Visible = SizeColumn;    NonVisualDataModule->LocalCalculateDirectorySizesPopupItem->Visible = SizeColumn;  }  TCustomListView * ListView = DebugNotNull(dynamic_cast<TCustomListView *>(Sender));  TPoint ScreenPoint = ListView->ClientToScreen(Point);  ScreenPoint.x -= GetScrollPos(ListView->Handle, SB_HORZ);  DirViewColumnMenu->Popup(ScreenPoint.x, ScreenPoint.y);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewExecFile(      TObject *Sender, TListItem *Item, bool &AllowExec){  DoDirViewExecFile(Sender, Item, AllowExec);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoDirViewExecFile(TObject * Sender,  TListItem * Item, bool & AllowExec){  DebugAssert(Sender && Item && Configuration);  DebugAssert(AllowExec);  TCustomDirView * ADirView = (TCustomDirView *)Sender;  TOperationSide Side = ((ADirView == DirView(osRemote)) ? osRemote : osLocal);  bool Remote = !IsSideLocalBrowser(Side);  DebugAssert(Item == ADirView->ItemFocused);  bool IsDirectory = ADirView->ItemIsDirectory(Item);  TResolvedDoubleClickAction Action;  if (FForceExecution)  {    Action = IsDirectory ? rdcaChangeDir : rdcaOpen;  }  else  {    TTerminal * ATerminal = !IsSideLocalBrowser(Side) ? Terminal : NULL;    Action = WinConfiguration->ResolveDoubleClickAction(IsDirectory, ATerminal);  }  if (Action == rdcaCopy)  {    // To counter the lock in DirViewBusy (called from TCustomDirView.DoExecute)    UnlockWindow();    try    {      if (IsLocalBrowserMode())      {        LocalLocalCopy(foCopy, Side, true, !WinConfiguration->CopyOnDoubleClickConfirmation, false, 0);      }      else      {        if (HasActiveTerminal())        {          ExecuteFileOperation(foCopy, Side, true, !WinConfiguration->CopyOnDoubleClickConfirmation);        }      }    }    __finally    {      LockWindow();    }    AllowExec = false;  }  else if (Action == rdcaEdit)  {    if (!Remote || !WinConfiguration->DisableOpenEdit)    {      ExecuteFile(Side, efDefaultEditor);      AllowExec = false;    }  }  else if (Action == rdcaOpen)  {    if (DebugAlwaysTrue(!IsDirectory) && Remote && !WinConfiguration->DisableOpenEdit)    {      ExecuteFile(osRemote, efShell);      AllowExec = false;    }  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::GetHasDirView(TOperationSide Side){  return ((Side == osRemote) || (Side == osCurrent));}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CompareDirectories(){  DebugFail();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SynchronizeDirectories(){  DebugFail();}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::DoSynchronizeDirectories(  UnicodeString & LocalDirectory, UnicodeString & RemoteDirectory, int UseDefaults){  TSynchronizeParamType Params;  Params.LocalDirectory = LocalDirectory;  Params.RemoteDirectory = RemoteDirectory;  int UnusedParams =    (GUIConfiguration->SynchronizeParams &      (TTerminal::spPreviewChanges | TTerminal::spTimestamp | TTerminal::spNotByTime | TTerminal::spBySize |       TTerminal::spCaseSensitive | TTerminal::spMirror | TTerminal::spByChecksum));  Params.Params = GUIConfiguration->SynchronizeParams & ~UnusedParams;  Params.Options = GUIConfiguration->SynchronizeOptions;  bool SaveSettings = false;  TSynchronizeController Controller(&DoSynchronize, &DoSynchronizeInvalid,    &DoSynchronizeTooManyDirectories);  DebugAssert(FSynchronizeController == NULL);  FSynchronizeController = &Controller;  bool Result;  try  {    TCopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;    int CopyParamAttrs = Terminal->UsableCopyParamAttrs(0).Upload;    int Options =      FLAGMASK(SynchronizeAllowSelectedOnly(), soAllowSelectedOnly);    DebugAssert(FOnFeedSynchronizeError == NULL);    DebugAssert(FOnSynchronizeAbort == NULL);    DebugAssert(FSynchronizeTerminal == NULL);    FSynchronizeTerminal = Terminal;    Result = DoSynchronizeDialog(Params, &CopyParam, Controller.StartStop,      SaveSettings, Options, CopyParamAttrs, GetSynchronizeOptions, SynchronizeSessionLog,      FOnFeedSynchronizeError, FOnSynchronizeAbort, SynchronizeInNewWindow, UseDefaults);    if (Result)    {      if (SaveSettings)      {        GUIConfiguration->SynchronizeParams = Params.Params | UnusedParams;        GUIConfiguration->SynchronizeOptions = Params.Options;      }      else      {        if (FLAGSET(GUIConfiguration->SynchronizeOptions, soSynchronizeAsk) &&            FLAGCLEAR(Params.Options, soSynchronizeAsk) &&            FLAGSET(Params.Options, soSynchronize))        {          GUIConfiguration->SynchronizeOptions =            (GUIConfiguration->SynchronizeOptions & ~soSynchronizeAsk) |            soSynchronize;        }      }      LocalDirectory = Params.LocalDirectory;      RemoteDirectory = Params.RemoteDirectory;    }  }  __finally  {    FSynchronizeController = NULL;    DebugAssert(FOnFeedSynchronizeError == NULL);    FOnFeedSynchronizeError = NULL;    DebugAssert(FOnSynchronizeAbort == NULL);    FOnSynchronizeAbort = NULL;    FSynchronizeTerminal = NULL;  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoSynchronize(  TSynchronizeController * /*Sender*/, const UnicodeString LocalDirectory,  const UnicodeString RemoteDirectory, const TCopyParamType & CopyParam,  const TSynchronizeParamType & Params, TSynchronizeChecklist ** Checklist,  TSynchronizeOptions * Options, bool Full){  // Keep-up-to-date mode  if (Terminal->Status == ssOpened)  {    try    {      int PParams = Params.Params;      if (!Full)      {        PParams |= TTerminal::spNoRecurse | TTerminal::spUseCache | TTerminal::spDelayProgress;        if (FLAGSET(Params.Options, soRecurse))        {          PParams |= TTerminal::spSubDirs;        }      }      else      {        // if keepuptodate is non-recursive,        // full sync before has to be non-recursive as well        if (FLAGCLEAR(Params.Options, soRecurse))        {          PParams |= TTerminal::spNoRecurse;        }      }      Synchronize(LocalDirectory, RemoteDirectory, smRemote, CopyParam,        PParams, Checklist, Options);    }    catch (Exception & E)    {      if (!Terminal->Active)      {        ShowExtendedExceptionEx(Terminal, &E);        // Do not abort the "keep up to date" when the session was succesfully reconnected.        if (!Terminal->Active)        {          throw;        }      }      else      {        if (FLAGSET(Params.Options, soContinueOnError) &&            DebugAlwaysTrue(FOnFeedSynchronizeError != NULL))        {          // noop, already logged in MoreMessageDialog        }        else        {          // We get mostly EAbort here, so this is noop.          // Exception is an error when listing directories while looking for differences.          ShowExtendedExceptionEx(Terminal, &E);          throw;        }      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoSynchronizeInvalid(  TSynchronizeController * /*Sender*/, const UnicodeString Directory,  const UnicodeString ErrorStr){  if (!Directory.IsEmpty())  {    SimpleErrorDialog(FMTLOAD(WATCH_ERROR_DIRECTORY, (Directory)), ErrorStr);  }  else  {    SimpleErrorDialog(LoadStr(WATCH_ERROR_GENERAL), ErrorStr);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoSynchronizeTooManyDirectories(  TSynchronizeController * /*Sender*/, int & MaxDirectories){  if (MaxDirectories < GUIConfiguration->MaxWatchDirectories)  {    MaxDirectories = GUIConfiguration->MaxWatchDirectories;  }  else  {    TMessageParams Params(mpNeverAskAgainCheck);    unsigned int Result = MessageDialog(      FMTLOAD(TOO_MANY_WATCH_DIRECTORIES, (MaxDirectories, MaxDirectories)),      qtConfirmation, qaYes | qaNo, HELP_TOO_MANY_WATCH_DIRECTORIES, &Params);    if ((Result == qaYes) || (Result == qaNeverAskAgain))    {      MaxDirectories *= 2;      if (Result == qaNeverAskAgain)      {        GUIConfiguration->MaxWatchDirectories = MaxDirectories;      }    }    else    {      Abort();    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::Synchronize(const UnicodeString LocalDirectory,  const UnicodeString RemoteDirectory, TSynchronizeMode Mode,  const TCopyParamType & CopyParam, int Params, TSynchronizeChecklist ** Checklist,  TSynchronizeOptions * Options){  // Keep-up-to-date mode  DebugAssert(!FAutoOperation);  void * BatchStorage;  BatchStart(BatchStorage);  FAutoOperation = true;  bool AnyOperation = false;  TDateTime StartTime = Now();  TSynchronizeChecklist * AChecklist = NULL;  try  {    FSynchronizeProgressForm = new TSynchronizeProgressForm(Application, true, -1);    if (FLAGCLEAR(Params, TTerminal::spDelayProgress))    {      FSynchronizeProgressForm->Start();    }    AChecklist = Terminal->SynchronizeCollect(LocalDirectory, RemoteDirectory,      static_cast<TTerminal::TSynchronizeMode>(Mode),      &CopyParam, Params | TTerminal::spNoConfirmation, TerminalSynchronizeDirectory,      Options);    SetTaskbarListProgressState(TBPF_NOPROGRESS);    SAFE_DESTROY(FSynchronizeProgressForm);    AnyOperation = (AChecklist->CheckedCount > 0);    if (AnyOperation)    {      TSynchronizeProgress SynchronizeProgress(AChecklist);      CreateProgressForm(&SynchronizeProgress);      try      {        Terminal->SynchronizeApply(          AChecklist, &CopyParam, Params | TTerminal::spNoConfirmation, TerminalSynchronizeDirectory,          SynchronizeProcessedItem, NULL, NULL, NULL);      }      __finally      {        DestroyProgressForm();      }    }  }  __finally  {    if (Checklist == NULL)    {      delete AChecklist;    }    else    {      *Checklist = AChecklist;    }    FAutoOperation = false;    SAFE_DESTROY(FSynchronizeProgressForm);    BatchEnd(BatchStorage);    ReloadLocalDirectory();    if (AnyOperation)    {      OperationComplete(StartTime);    }  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::SynchronizeAllowSelectedOnly(){  // can be called from command line  return Visible &&    ((DirView(osRemote)->SelCount > 0) ||     (HasDirView[osLocal] && (DirView(osLocal)->SelCount > 0)));}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SynchronizeSessionLog(const UnicodeString & Message){  LogSynchronizeEvent(Terminal, Message);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::GetSynchronizeOptions(  int Params, TSynchronizeOptions & Options){  DebugAssert(!IsLocalBrowserMode());  if (FLAGSET(Params, TTerminal::spSelectedOnly) && SynchronizeAllowSelectedOnly())  {    Options.Filter = new TStringList();    Options.Filter->CaseSensitive = false;    Options.Filter->Duplicates = Types::dupAccept;    if (DirView(osRemote)->SelCount > 0)    {      DirView(osRemote)->CreateFileList(false, false, Options.Filter);    }    if (HasDirView[osLocal] && (DirView(osLocal)->SelCount > 0))    {      DirView(osLocal)->CreateFileList(false, false, Options.Filter);    }    Options.Filter->Sort();  }}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::SerializeCopyParamForCommandLine(const TCopyParamType * CopyParams){  TCopyParamType Defaults;  std::unique_ptr<THierarchicalStorage> ConfigStorage(Configuration->CreateConfigStorage());  ConfigStorage->AccessMode = smRead;  if (ConfigStorage->OpenSubKey(Configuration->ConfigurationSubKey, false))  {    GUIConfiguration->LoadCopyParam(ConfigStorage.get(), &Defaults);  }  ConfigStorage.reset(NULL);  std::unique_ptr<TStringList> Options(new TStringList());  std::unique_ptr<TOptionsStorage> OptionsStorage(new TOptionsStorage(Options.get(), true));  CopyParams->Save(OptionsStorage.get(), &Defaults);  UnicodeString Result;  if (Options->Count > 0)  {    Result =      FORMAT(L" %s%s", (TProgramParams::FormatSwitch(RAWTRANSFERSETTINGS_SWITCH), StringsToParams(Options.get())));  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SynchronizeInNewWindow(  const TSynchronizeParamType & Params, const TCopyParamType * CopyParams){  UnicodeString SessionName = CreateHiddenDuplicateSession();  UnicodeString AdditionalParams =    FORMAT(L"%s%s %s // \"%s\" \"%s\" %d %d", (      TProgramParams::FormatSwitch(DEFAULTS_SWITCH),      SerializeCopyParamForCommandLine(CopyParams),      TProgramParams::FormatSwitch(KEEP_UP_TO_DATE_SWITCH),      Params.LocalDirectory, Params.RemoteDirectory, Params.Params, Params.Options));  ExecuteNewInstance(SessionName, AdditionalParams);}//---------------------------------------------------------------------------struct TSynchronizeParams{  UnicodeString LocalDirectory;  UnicodeString RemoteDirectory;  TSynchronizeMode Mode;  TSynchronizeChecklist * Checklist;  int Params;  TCopyParamType * CopyParam;  TDateTime CollectElapsed;  TDateTime * StartTime;  TProcessedSynchronizationChecklistItem OnProcessedItem;};//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FullSynchronize(  TSynchronizeParams & Params, TProcessedSynchronizationChecklistItem OnProcessedItem,  TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems){  DebugAssert(!FAutoOperation);  void * BatchStorage;  BatchStart(BatchStorage);  FAutoOperation = true;  TFileOperationStatistics Statistics;  TDateTime Start = Now();  try  {    Params.OnProcessedItem = OnProcessedItem;    TSynchronizeProgress SynchronizeProgress(Params.Checklist);    CreateProgressForm(&SynchronizeProgress);    Terminal->SynchronizeApply(      Params.Checklist, Params.CopyParam, Params.Params | TTerminal::spNoConfirmation,      TerminalSynchronizeDirectory, SynchronizeProcessedItem, OnUpdatedSynchronizationChecklistItems, &Params,      &Statistics);  }  __finally  {    Params.OnProcessedItem = NULL;    FAutoOperation = false;    DestroyProgressForm();    BatchEnd(BatchStorage);    ReloadLocalDirectory();  }  if (WinConfiguration->SynchronizeSummary)  {    UnicodeString Message = MainInstructions(LoadStr(SYNCHRONIZE_COMPLETE)) + L"\n";    // The statistics should be 0 anyway in this case    if (FLAGCLEAR(Params.Params, TTerminal::spTimestamp))    {      Message += L"\n";      if (Statistics.FilesUploaded > 0)      {        Message += FORMAT(LoadStrPart(SYNCHRONIZE_SUMMARY, 1), (FormatNumber(Statistics.FilesUploaded), FormatBytes(Statistics.TotalUploaded))) + L"\n";      }      if (Statistics.FilesDownloaded > 0)      {        Message += FORMAT(LoadStrPart(SYNCHRONIZE_SUMMARY, 2), (FormatNumber(Statistics.FilesDownloaded), FormatBytes(Statistics.TotalDownloaded))) + L"\n";      }      if (Statistics.FilesDeletedLocal > 0)      {        Message += FORMAT(LoadStrPart(SYNCHRONIZE_SUMMARY, 3), (FormatNumber(Statistics.FilesDeletedLocal))) + L"\n";      }      if (Statistics.FilesDeletedRemote > 0)      {        Message += FORMAT(LoadStrPart(SYNCHRONIZE_SUMMARY, 4), (FormatNumber(Statistics.FilesDeletedRemote))) + L"\n";      }    }    TDateTime Elapsed = (Now() - Start);    Message +=      L"\n" +      FORMAT(LoadStrPart(SYNCHRONIZE_SUMMARY, 5), (FormatDateTimeSpan(Params.CollectElapsed))) + L"\n" +      FORMAT(LoadStrPart(SYNCHRONIZE_SUMMARY, 6), (FormatDateTimeSpan(Elapsed)));    TMessageParams Params(mpNeverAskAgainCheck);    unsigned int Result = MessageDialog(Message, qtInformation, qaOK, HELP_NONE, &Params);    if (Result == qaNeverAskAgain)    {      WinConfiguration->SynchronizeSummary = false;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SynchronizeProcessedItem(void * Token, const TSynchronizeChecklist::TItem * ChecklistItem){  if (DebugAlwaysTrue(FProgressForm != NULL) && DebugAlwaysTrue(FProgressForm->SynchronizeProgress != NULL))  {    FProgressForm->SynchronizeProgress->ItemProcessed(ChecklistItem);  }  // Not set in keep-up-to-date mode - Synchronize() method  if (Token != NULL)  {    TSynchronizeParams & Params = *static_cast<TSynchronizeParams *>(Token);    if (Params.OnProcessedItem != NULL)    {      Params.OnProcessedItem(NULL, ChecklistItem);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoFullSynchronize(  void * Token, TProcessedSynchronizationChecklistItem OnProcessedItem,  TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems){  TSynchronizeParams & Params = *static_cast<TSynchronizeParams *>(Token);  *Params.StartTime = Now();  FullSynchronize(Params, OnProcessedItem, OnUpdatedSynchronizationChecklistItems);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoSynchronizeChecklistCalculateSize(  TSynchronizeChecklist * Checklist, const TSynchronizeChecklist::TItemList & Items, void * Token){  // terminal can be already closed (e.g. dropped connection)  if (Terminal != NULL)  {    TSynchronizeParams & Params = *static_cast<TSynchronizeParams *>(Token);    Terminal->SynchronizeChecklistCalculateSize(Checklist, Items, Params.CopyParam);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoSynchronizeMove(  TOperationSide Side, TStrings * FileList, const UnicodeString & NewFileName, bool TargetIsDirectory, void * Token){  DebugAssert(!IsLocalBrowserMode());  TAutoBatch AutoBatch(this);  TAutoFlag AutoOperationFlag(FAutoOperation);  TSynchronizeParams & Params = *static_cast<TSynchronizeParams *>(Token);  if (Side == osRemote)  {    UnicodeString Target;    UnicodeString FileMask;    if (TargetIsDirectory)    {      Target = NewFileName;      Terminal->CreateTargetDirectory(Target, faDirectory, Params.CopyParam);    }    else    {      Target = UnixExtractFileDir(NewFileName);      FileMask = DelimitFileNameMask(UnixExtractFileName(NewFileName));    }    RemoteDirView->SaveSelection();    RemoteDirView->SaveSelectedNames();    try    {      Terminal->MoveFiles(FileList, Target, FileMask, false);    }    catch(...)    {      RemoteDirView->DiscardSavedSelection();      throw;    }    RemoteDirView->RestoreSelection();  }  else if (DebugAlwaysTrue(Side == osLocal))  {    std::unique_ptr<TStrings> Directories(CreateSortedStringList());    if (TargetIsDirectory)    {      if (!ForceDirectories(ApiPath(NewFileName)))      {        throw EOSExtException(FMTLOAD(CREATE_DIR_ERROR, (NewFileName)));      }      Directories->Add(NewFileName);    }    else    {      Directories->Add(ExtractFileDir(NewFileName));    }    for (int Index = 0; Index < FileList->Count; Index++)    {      UnicodeString FileName = FileList->Strings[Index];      UnicodeString Directory = ExtractFileDir(FileName);      Directories->Add(Directory);      UnicodeString NewFilePath = NewFileName;      if (TargetIsDirectory)      {        NewFilePath = TPath::Combine(NewFilePath, ExtractFileName(FileName));      }      if (!MoveFile(ApiPath(FileName).c_str(), ApiPath(NewFilePath).c_str()))      {        throw EOSExtException(FMTLOAD(RENAME_FILE_ERROR, (FileName, NewFilePath)));      }    }    for (int Index = 0; Index < Directories->Count; Index++)    {      ReloadLocalDirectory(Directories->Strings[Index]);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoSynchronizeBrowse(TOperationSide Side, TSynchronizeChecklist::TAction Action, const TSynchronizeChecklist::TItem * Item){  UnicodeString LocalPath = ExcludeTrailingBackslash(Item->Local.Directory);  if (Side == osLocal)  {    if (Action == TSynchronizeChecklist::saDownloadNew)    {      OpenFolderInExplorer(LocalPath);    }    else    {      OpenFileInExplorer(CombinePaths(LocalPath, Item->GetFileName()));    }  }  else if (DebugAlwaysTrue(Side == osRemote))  {    // Similar to CreateHiddenDuplicateSession, except that it modifies the initial directories    std::unique_ptr<TSessionData> SessionData(CloneCurrentSessionData());    SessionData->RemoteDirectory = UnixExcludeTrailingBackslash(Item->Remote.Directory);    if (!LocalPath.IsEmpty())    {      SessionData->LocalDirectory = LocalPath;    }    UnicodeString SessionName = SaveHiddenDuplicateSession(SessionData.get());    ExecuteNewInstance(SessionName, FORMAT(L"%s=\"%s\"", (TProgramParams::FormatSwitch(BROWSE_SWITCH), Item->GetFileName())));  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FullSynchronizeInNewWindow(  TSynchronizeMode Mode, int Params, const UnicodeString & LocalDirectory, const UnicodeString & RemoteDirectory,   const TCopyParamType * CopyParams){  UnicodeString SessionName = CreateHiddenDuplicateSession();  UnicodeString AdditionalParams =    FORMAT(L"%s%s %s // \"%s\" \"%s\" %d %d", (      TProgramParams::FormatSwitch(DEFAULTS_SWITCH),      SerializeCopyParamForCommandLine(CopyParams),      TProgramParams::FormatSwitch(SYNCHRONIZE_SWITCH),      LocalDirectory, RemoteDirectory, Mode, Params));  ExecuteNewInstance(SessionName, AdditionalParams);}//---------------------------------------------------------------------------int __fastcall TCustomScpExplorerForm::DoFullSynchronizeDirectories(  UnicodeString & LocalDirectory, UnicodeString & RemoteDirectory,  TSynchronizeMode & Mode, int Params, bool & SaveMode, int UseDefaults){  int Result;  bool SaveSettings = false;  int Options =    FLAGMASK(!Terminal->IsCapable[fcTimestampChanging], fsoDisableTimestamp) |    FLAGMASK(!CanCalculateChecksum(), fsoDisableByChecksum) |    FLAGMASK(SynchronizeAllowSelectedOnly(), fsoAllowSelectedOnly);  TCopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;  TUsableCopyParamAttrs CopyParamAttrs = Terminal->UsableCopyParamAttrs(0);  bool Continue =    ((UseDefaults == 0) ||     DoFullSynchronizeDialog(Mode, Params, LocalDirectory, RemoteDirectory,       &CopyParam, SaveSettings, SaveMode, Options, CopyParamAttrs, FullSynchronizeInNewWindow, UseDefaults)) &&    (FLAGCLEAR(Params, TTerminal::spByChecksum) || EnsureCommandSessionFallback(fcCalculatingChecksum));  if (Continue)  {    Configuration->Usage->Inc(L"Synchronizations");    CopyParam.IncludeFileMask.SetRoots(LocalDirectory, RemoteDirectory);    UpdateCopyParamCounters(CopyParam);    TSynchronizeOptions SynchronizeOptions;    GetSynchronizeOptions(Params, SynchronizeOptions);    if (SaveSettings)    {      GUIConfiguration->SynchronizeParams = Params;    }    else    {      SaveMode = false;    }    TDateTime StartTime = Now();    TSynchronizeChecklist * Checklist = NULL;    try    {      DebugAssert(!FAutoOperation);      FAutoOperation = true;      try      {        UnicodeString SessionKey = Terminal->SessionData->SessionKey;        std::unique_ptr<TStrings> DataList(Configuration->LoadDirectoryStatisticsCache(SessionKey, RemoteDirectory, CopyParam));        int Files = -1;        if (DataList->Count >= 1)        {          Files = StrToIntDef(DataList->Strings[0], Files);        }        else        {          DataList->Add(UnicodeString());        }        FSynchronizeProgressForm = new TSynchronizeProgressForm(Application, true, Files);        FSynchronizeProgressForm->Start();        Checklist = Terminal->SynchronizeCollect(LocalDirectory, RemoteDirectory,          static_cast<TTerminal::TSynchronizeMode>(Mode),          &CopyParam, Params | TTerminal::spNoConfirmation, TerminalSynchronizeDirectory,          &SynchronizeOptions);        if (Terminal->SessionData->CacheDirectories)        {          DataList->Strings[0] = IntToStr(SynchronizeOptions.Files);          Configuration->SaveDirectoryStatisticsCache(SessionKey, RemoteDirectory, CopyParam, DataList.get());        }      }      __finally      {        FAutoOperation = false;        SetTaskbarListProgressState(TBPF_NOPROGRESS);        SAFE_DESTROY(FSynchronizeProgressForm);      }      TSynchronizeParams SynchronizeParams;      SynchronizeParams.LocalDirectory = LocalDirectory;      SynchronizeParams.RemoteDirectory = RemoteDirectory;      SynchronizeParams.Mode = Mode;      SynchronizeParams.CopyParam = &CopyParam;      SynchronizeParams.Params = Params;      SynchronizeParams.Checklist = Checklist;      SynchronizeParams.CollectElapsed = (Now() - StartTime);      SynchronizeParams.StartTime = &StartTime;      SynchronizeParams.OnProcessedItem = NULL;      Result = Checklist->Count;      if (Checklist->Count > 0)      {        if (FLAGSET(Params, TTerminal::spPreviewChanges))        {          if (!DoSynchronizeChecklistDialog(                Checklist, Mode, Params, LocalDirectory, RemoteDirectory, CustomCommandMenu, DoFullSynchronize,                DoSynchronizeChecklistCalculateSize, DoSynchronizeMove, DoSynchronizeBrowse, &SynchronizeParams))          {            Result = -1;          }        }        else        {          FullSynchronize(SynchronizeParams, NULL, NULL);        }      }      else      {        UnicodeString Message = MainInstructions(LoadStr(COMPARE_NO_DIFFERENCES));        MessageDialog(Message, qtInformation, qaOK, HELP_SYNCHRONIZE_NO_DIFFERENCES);      }    }    __finally    {      delete Checklist;    }    OperationComplete(StartTime);  }  else  {    Result = -1;  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TerminalSynchronizeDirectory(  const UnicodeString & LocalDirectory, const UnicodeString & RemoteDirectory,  bool & Continue, bool Collect, const TSynchronizeOptions * Options){  if (Collect)  {    DebugAssert(FSynchronizeProgressForm != NULL);    if (!FSynchronizeProgressForm->Started)    {      FSynchronizeProgressForm->Start();    }    int CompareProgress = FSynchronizeProgressForm->SetData(LocalDirectory, RemoteDirectory, Options->Files, Continue);    SetTaskbarListProgressValue(CompareProgress);  }  else  {    DebugAssert(FSynchronizeProgressForm == NULL);    DebugAssert(FProgressForm != NULL);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::StandaloneEdit(const UnicodeString & FileName){  UnicodeString FullFileName = AbsolutePath(Terminal->CurrentDirectory, FileName);  std::unique_ptr<TRemoteFile> File(Terminal->ReadFile(FullFileName));  if (File.get() != NULL)  {    ExecuteRemoteFile(FullFileName, File.get(), efInternalEditor);    Application->ShowMainForm = false;    Application->Run();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExploreLocalDirectory(TOperationSide){  DebugFail();}//---------------------------------------------------------------------------TSessionData * __fastcall TCustomScpExplorerForm::CloneCurrentSessionData(){  std::unique_ptr<TSessionData> SessionData(new TSessionData(L""));  SessionData->Assign(ManagedSession->SessionData);  UpdateSessionData(SessionData.get());  DebugAssert(SessionData->IsLocalBrowser == IsLocalBrowserMode());  if (IsActiveTerminal(ManagedSession))  {    ManagedSession->UpdateSessionCredentials(SessionData.get());  }  if (!ManagedSession->SessionData->HasSessionName())  {    // Particularly for "Workspace/XXXX" name, we need to reset it, as it would become user-visible    // once IsWorkspace is cleared    SessionData->Name = UnicodeString();  }  // Most uses of this method ends with saving the session, and we do not want to store the IsWorkspace flag.  // Particularly, with SaveHiddenDuplicateSession, it won't work as TSessionData::ParseUrl explicitly ignored workspace sessions.  SessionData->IsWorkspace = false;  return SessionData.release();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SaveCurrentSession(){  TSessionData * SessionData = CloneCurrentSessionData();  try  {    TSessionData * EditingSessionData = StoredSessions->FindSame(SessionData);    DoSaveSession(SessionData, EditingSessionData, true, NULL);  }  __finally  {    delete SessionData;  }}//---------------------------------------------------------------------------TObjectList * __fastcall TCustomScpExplorerForm::DoCollectWorkspace(){  TTerminalManager * Manager = TTerminalManager::Instance();  std::unique_ptr<TObjectList> DataList(new TObjectList());  if (DebugAlwaysTrue(ManagedSession != NULL))  {    // Update ManagedSession->StateData    UpdateSession(ManagedSession);  }  Manager->SaveWorkspace(DataList.get());  return DataList.release();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoSaveWorkspace(  const UnicodeString & Name, TObjectList * DataList, bool SavePasswords, bool Explicit){  WinConfiguration->LastWorkspace = Name;  if (!SavePasswords)  {    for (int Index = 0; Index < DataList->Count; Index++)    {      TSessionData * SessionData = dynamic_cast<TSessionData *>(DataList->Items[Index]);      if (SessionData->Link.IsEmpty())      {        SessionData->ClearSessionPasswords();      }    }  }  StoredSessions->NewWorkspace(Name, DataList);  // modified only  StoredSessions->Save(false, Explicit);}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::WorkspaceName(){  return    DefaultStr(WinConfiguration->LastWorkspace,      DefaultStr(WinConfiguration->AutoWorkspace, LoadStr(NEW_WORKSPACE)));}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::SaveWorkspace(bool EnableAutoSave){  std::unique_ptr<TObjectList> DataList(DoCollectWorkspace());  bool AnyNonStoredSessionWithPassword = false;  bool AnyNonStoredNonWorkspaceSessionWithPassword = false;  bool AllNonStoredSessionsAnonymous = true;  TTerminalManager * Manager = TTerminalManager::Instance();  for (int Index = 0; Index < DataList->Count; Index++)  {    TSessionData * SessionData = dynamic_cast<TSessionData *>(DataList->Items[Index]);    if (SessionData->Link.IsEmpty())    {      if (SessionData->HasAnySessionPassword())      {        AnyNonStoredSessionWithPassword = true;        if (!Manager->Sessions[Index]->SessionData->IsWorkspace)        {          AnyNonStoredNonWorkspaceSessionWithPassword = true;        }      }      if (!SameText(SessionData->UserName, AnonymousUserName))      {        AllNonStoredSessionsAnonymous = false;      }    }  }  bool SavePasswords;  bool * PSavePasswords;  bool NotRecommendedSavingPasswords =    !CustomWinConfiguration->UseMasterPassword &&    !AllNonStoredSessionsAnonymous;  if (Configuration->DisablePasswordStoring ||      !AnyNonStoredSessionWithPassword)  {    PSavePasswords = NULL;    SavePasswords = false;  }  else  {    PSavePasswords = &SavePasswords;    SavePasswords =      !AnyNonStoredNonWorkspaceSessionWithPassword ||      !NotRecommendedSavingPasswords;  }  UnicodeString Name = WorkspaceName();  bool CreateShortcut = false;  bool Result =    DoSaveWorkspaceDialog(      Name, PSavePasswords, NotRecommendedSavingPasswords, CreateShortcut,      EnableAutoSave);  if (Result)  {    DoSaveWorkspace(Name, DataList.get(), SavePasswords, true);    if (CreateShortcut)    {      TOperationVisualizer Visualizer;      UnicodeString AdditionalParams = TProgramParams::FormatSwitch(DESKTOP_SWITCH);      CreateDesktopSessionShortCut(Name, L"", AdditionalParams, -1, WORKSPACE_ICON);    }    if (EnableAutoSave)    {      WinConfiguration->AutoSaveWorkspace = true;      WinConfiguration->AutoWorkspace = Name;      if (PSavePasswords != NULL)      {        WinConfiguration->AutoSaveWorkspacePasswords = SavePasswords;      }    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateSession(TManagedTerminal * Session){  DebugAssert(IsLocalBrowserMode() == Session->LocalBrowser);  DebugAssert(Session == ManagedSession);  if (!IsLocalBrowserMode())  {    SAFE_DESTROY(Session->RemoteExplorerState);    if (WinConfiguration->PreservePanelState)    {      Session->RemoteExplorerState = RemoteDirView->SaveState();    }  }  UpdateSessionData(Session->StateData);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateSessionData(TSessionData * Data){  // Keep in sync with TSessionData::CopyStateData  DebugAssert(Data != NULL);  // This is inconsistent with how color (for example) is handled.  Data->Name = ManagedSession->SessionData->Name;  if (!IsLocalBrowserMode())  {    // cannot use RemoteDirView->Path, because it is empty if connection    // was already closed    // also only peek, we may not be connected at all atm    // so make sure we do not try retrieving current directory from the server    // (particularly with FTP)    UnicodeString ACurrentDirectory = Terminal->PeekCurrentDirectory();    if (!ACurrentDirectory.IsEmpty())    {      Data->RemoteDirectory = ACurrentDirectory;    }  }  Data->Color = SessionColor;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ToolBarResize(TObject *Sender){  TTBXToolbar * Toolbar = dynamic_cast<TTBXToolbar*>(Sender);  DebugAssert(Toolbar != NULL);  for (int i = 0; i < Toolbar->Items->Count; i++)  {    TTBXCustomDropDownItem * DropDownItem;    DropDownItem = dynamic_cast<TTBXCustomDropDownItem *>(Toolbar->Items->Items[i]);    if (DropDownItem != NULL)    {      ToolbarItemResize(DropDownItem,        Toolbar->Width - (Toolbar->View->BaseSize.x - DropDownItem->EditWidth) -        Toolbar->NonClientWidth);      break;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ToolbarItemResize(TTBXCustomDropDownItem * Item, int Width){  Item->EditWidth = Width;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ToolbarGetBaseSize(  TTBCustomToolbar * Toolbar, TPoint & ASize){  for (int i = 0; i < Toolbar->Items->Count; i++)  {    TTBXCustomDropDownItem * DropDownItem;    DropDownItem = dynamic_cast<TTBXCustomDropDownItem *>(Toolbar->Items->Items[i]);    if (DropDownItem != NULL)    {      ASize.x -= DropDownItem->EditWidth;      TControl * Control = this;      ASize.x += ScaleByTextHeight(Control, 50) /* minimal combo width */;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoWarnLackOfTempSpace(  const UnicodeString Path, __int64 RequiredSpace, bool & Continue){  if (WinConfiguration->DDWarnLackOfTempSpace)  {    UnicodeString ADrive = ExtractFileDrive(ExpandFileName(Path));    if (!ADrive.IsEmpty())    {      __int64 FreeSpace = DiskFree((Byte)(ADrive[1]-'A'+1));      DebugAssert(RequiredSpace >= 0);      __int64 RequiredWithReserve;      RequiredWithReserve = (__int64)(RequiredSpace * WinConfiguration->DDWarnLackOfTempSpaceRatio);      if (FreeSpace < RequiredWithReserve)      {        unsigned int Result;        TMessageParams Params(mpNeverAskAgainCheck);        Result = MessageDialog(FMTLOAD(DD_WARN_LACK_OF_TEMP_SPACE, (Path,          FormatBytes(FreeSpace), FormatBytes(RequiredSpace))),          qtWarning, qaYes | qaNo, HELP_DD_WARN_LACK_OF_TEMP_SPACE, &Params);        if (Result == qaNeverAskAgain)        {          WinConfiguration->DDWarnLackOfTempSpace = false;        }        Continue = (Result == qaYes || Result == qaNeverAskAgain);      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AddBookmark(TOperationSide Side){  DoOpenDirectoryDialog(odAddBookmark, Side);}//---------------------------------------------------------------------------TStrings * __fastcall TCustomScpExplorerForm::CreateVisitedDirectories(TOperationSide Side){  // we should better use TCustomDirView::FCaseSensitive, but it is private  TStringList * VisitedDirectories = CreateSortedStringList(!IsSideLocalBrowser(Side));  try  {    TCustomDirView * DView = DirView(Side);    for (int Index = -DView->BackCount; Index <= DView->ForwardCount; Index++)    {      VisitedDirectories->Add(DView->HistoryPath[Index]);    }  }  catch (...)  {    delete VisitedDirectories;    throw;  }  return VisitedDirectories;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoOpenDirectoryDialog(  TOpenDirectoryMode Mode, TOperationSide Side){  bool Continue = true;  if (Mode == odAddBookmark)  {    TMessageParams Params(mpNeverAskAgainCheck);    Params.NeverAskAgainTitle = LoadStr(ADD_BOOKMARK_SHARED);    Params.NeverAskAgainCheckedInitially = WinConfiguration->UseSharedBookmarks;    UnicodeString Message = MainInstructions(FMTLOAD(ADD_BOOKMARK_CONFIRM, (DirView(Side)->PathName)));    unsigned int Answer =      MessageDialog(Message,        qtConfirmation, qaOK | qaCancel, HELP_ADD_BOOKMARK_CONFIRM, &Params);    if (Answer == qaNeverAskAgain)    {      Continue = true;      WinConfiguration->UseSharedBookmarks = true;    }    else if (Answer == qaOK)    {      Continue = true;      WinConfiguration->UseSharedBookmarks = false;    }    else    {      Continue = false;    }  }  if (Continue)  {    TStrings * VisitedDirectories = CreateVisitedDirectories(Side);    try    {      UnicodeString Name = DirView(Side)->PathName;      bool Repeat;      do      {        Repeat = false;        TOperationSide BookmarkSide = IsSideLocalBrowser(Side) ? osLocal : osRemote;        if (::DoOpenDirectoryDialog(Mode, BookmarkSide, Name, VisitedDirectories, Terminal,              // do not allow switching to location profiles,              // if we are not connected              HasDirView[osLocal] && IsActiveTerminal(Terminal)))        {          TWindowLock Lock(this);          if (!TryOpenDirectory(Side, Name))          {            Repeat = true;            Mode = odBrowse;          }        }      }      while (Repeat);    }    __finally    {      delete VisitedDirectories;    }  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CommandSessionFallback(){  DebugAssert(!Terminal->CommandSessionOpened);  return TTerminalManager::Instance()->ConnectTerminal(Terminal->CommandSession);}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::EnsureCommandSessionFallback(TFSCapability Capability){  bool Result = Terminal->IsCapable[Capability] ||    Terminal->CommandSessionOpened;  if (!Result)  {    // We might get here for example when "checksum" synchronization is requested from command-line    // on server that supports neither checksum nor shell    if (!Terminal->IsCapable[fcSecondaryShell])    {      NotSupported();    }    else if (!GUIConfiguration->ConfirmCommandSession)    {      Result = true;    }    else    {      TMessageParams Params(mpNeverAskAgainCheck);      const TFileSystemInfo & FileSystemInfo = Terminal->GetFileSystemInfo();      unsigned int Answer = MessageDialog(FMTLOAD(PERFORM_ON_COMMAND_SESSION2,        (FileSystemInfo.ProtocolName, FileSystemInfo.ProtocolName)), qtConfirmation,        qaOK | qaCancel, HELP_PERFORM_ON_COMMAND_SESSION, &Params);      if (Answer == qaNeverAskAgain)      {        GUIConfiguration->ConfirmCommandSession = false;        Result = true;      }      else if (Answer == qaOK)      {        Result = true;      }    }    if (Result)    {      Result = CommandSessionFallback();    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::OpenConsole(UnicodeString Command){  if (EnsureCommandSessionFallback(fcAnyCommand))  {    DoConsoleDialog(Terminal, Command);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileControlDDDragEnter(      TObject *Sender, _di_IDataObject /*DataObj*/, int /*grfKeyState*/,      const TPoint & /*Point*/, int & /*dwEffect*/, bool & Accept){  if (!IsSideLocalBrowser(osRemote) &&      IsFileControl(DropSourceControl, osRemote) &&      (FDDExtMapFile != NULL))  {    Accept = true;  }  FDDTargetControl = dynamic_cast<TControl*>(Sender);  DebugAssert(FDDTargetControl != NULL);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsDDDragEnter(  _di_IDataObject DataObj, int KeyState,  const TPoint & Point, int & Effect, bool & Accept){  FileControlDDDragEnter(SessionsPageControl, DataObj, KeyState, Point, Effect, Accept);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueDDDragEnter(  _di_IDataObject DataObj, int KeyState,  const TPoint & Point, int & Effect, bool & Accept){  FileControlDDDragEnter(QueueView3, DataObj, KeyState, Point, Effect, Accept);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileControlDDDragLeave(  TObject * Sender){  DebugUsedParam(Sender);  DebugAssert(FDDTargetControl == Sender);  FDDTargetControl = NULL;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsDDDragLeave(int){  FileControlDDDragLeave(SessionsPageControl);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueDDDragLeave(int){  FileControlDDDragLeave(QueueView3);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AddEditLink(TOperationSide Side, bool Add){  DebugAssert(!IsSideLocalBrowser(Side));  DebugUsedParam(Side);  bool Edit = false;  TRemoteFile * File = NULL;  UnicodeString FileName;  UnicodeString PointTo;  bool SymbolicLink = true;  if (RemoteDirView->ItemFocused)  {    DebugAssert(RemoteDirView->ItemFocused->Data);    File = (TRemoteFile *)RemoteDirView->ItemFocused->Data;    Edit = !Add && File->IsSymLink && Terminal->SessionData->ResolveSymlinks;    if (Edit)    {      FileName = File->FileName;      PointTo = File->LinkTo;    }    else if (!File->IsParentDirectory)    {      PointTo = File->FileName;    }  }  if (DoSymlinkDialog(FileName, PointTo, osRemote, SymbolicLink, Edit,        Terminal->IsCapable[fcHardLink]))  {    Configuration->Usage->Inc(L"RemoteLinksCreated");    if (Edit)    {      DebugAssert(File->FileName == FileName);      int Params = dfNoRecursive;      Terminal->ExceptionOnFail = true;      try      {        Terminal->DeleteFile(L"", File, &Params);      }      __finally      {        Terminal->ExceptionOnFail = false;      }    }    Terminal->CreateLink(FileName, PointTo, SymbolicLink);  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanAddEditLink(TOperationSide Side){  return    (IsSideLocalBrowser(Side) ||     (HasActiveTerminal() &&      Terminal->ResolvingSymlinks &&      Terminal->IsCapable[fcSymbolicLink]));}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::LinkFocused(){  return    !IsSideLocalBrowser(FCurrentSide) &&    (RemoteDirView->ItemFocused != NULL) &&    ((TRemoteFile *)RemoteDirView->ItemFocused->Data)->IsSymLink &&    Terminal->SessionData->ResolveSymlinks;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecuteCurrentFile(){  DebugAssert(!WinConfiguration->DisableOpenEdit);  FForceExecution = true;  try  {    DirView(osCurrent)->ExecuteCurrentFile();  }  __finally  {    FForceExecution = false;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecuteCurrentFileWith(bool OnFocused){  TEditorData ExternalEditor;  ExternalEditor.Editor = edExternal;  bool Remember = false;  if (DoEditorPreferencesDialog(&ExternalEditor, Remember, epmAdHoc, !IsSideLocalBrowser(osCurrent)))  {    if (Remember)    {      TEditorList * EditorList = new TEditorList;      try      {        *EditorList = *WinConfiguration->EditorList;        bool Found = false;        int i = 0;        while (!Found && (i < EditorList->Count))        {          const TEditorPreferences * Editor = EditorList->Editors[i];          if ((Editor->Data->Editor == edExternal) &&              (Editor->Data->ExternalEditor == ExternalEditor.ExternalEditor))          {            Found = true;          }          i++;        }        if (!Found)        {          EditorList->Add(new TEditorPreferences(ExternalEditor));          WinConfiguration->EditorList = EditorList;        }      }      __finally      {        delete EditorList;      }    }    ExecuteFile(osCurrent, efExternalEditor, &ExternalEditor, true, OnFocused);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DetachTerminal(TObject * ATerminal){  if (FFileFindTerminal == ATerminal)  {    FFileFindTerminal = NULL;    HideFileFindDialog();  }  if (FClipboardTerminal == ATerminal)  {    ClipboardClear(); // implies ClipboardStop  }  if ((FOnSynchronizeAbort != NULL) &&      (ATerminal == FManagedSession))  {    FOnSynchronizeAbort(NULL);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TerminalRemoved(TObject * Sender){  FEditorManager->ProcessFiles(FileTerminalRemoved, Sender);  DetachTerminal(Sender);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileTerminalReplaced(  const UnicodeString FileName, TEditedFileData * Data, TObject * /*Token*/, void * Arg){  TManagedTerminal * ATerminal = static_cast<TManagedTerminal *>(Arg);  if (Data->Terminal == Terminal)  {    Data->Terminal = ATerminal;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileTerminalRemoved(const UnicodeString FileName,  TEditedFileData * Data, TObject * /*Token*/, void * Arg){  TTerminal * Terminal = static_cast<TTerminal *>(Arg);  DebugAssert(Terminal != NULL);  if (Data->Terminal == Terminal)  {    Data->Terminal = NULL;  }}//---------------------------------------------------------------------------TManagedTerminal * TCustomScpExplorerForm::GetReplacementForLastSession(){  return NULL;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LastTerminalClosed(){  UpdateControls();  SessionColor = TColor(0);  UpdateRemotePathComboBox(false);  NeedSession(false);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::NeedSession(bool Startup){  try  {    // Cache, as the login dialog can change its value.    // See also DoShow. Also see TTerminalManager::NewSession.    bool ShowLogin = WinConfiguration->ShowLoginWhenNoSession;    try    {      if (ShowLogin)      {        bool ReloadSessions = !Startup;        TTerminalManager::Instance()->NewSession(L"", ReloadSessions, this, true);      }    }    __finally    {      // Do not terminate, if we are only starting up and we are not showing Login dialog      // (so there was no chance for the user to open any session yet)      if ((ShowLogin || !Startup) &&          !WinConfiguration->KeepOpenWhenNoSession &&          // this rules out the implicit Commander's local-local browser          ((Terminal == NULL) || (!Terminal->Active && !Terminal->Permanent)))      {        TerminateApplication();      }    }  }  catch (EAbort &)  {    // swallow    // The TTerminalManager does not expect the OnLastTerminalClose to throw without trying to connect.    // Also when called from TWinControl.UpdateShowing => CMShowingChanged, the showing is aborted on exception  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionListChanged(bool ForceTruncationUpdate){  TTerminalManager * Manager = TTerminalManager::Instance();  DebugAssert(!Manager->Updating);  TAutoFlag UpdatingSessionTabsFlag(FUpdatingSessionTabs);  int ActiveSessionIndex = Manager->ActiveSessionIndex;  Configuration->Usage->SetMax(L"MaxOpenedSessions", Manager->Count);  SessionsPageControl->LockDrawing();  try  {    int PrevTabsWidth = SessionsPageControl->TotalTabsWidth();    while (SessionsPageControl->PageCount > Manager->Count + 1)    {      delete SessionsPageControl->Pages[SessionsPageControl->PageCount - 1];    }    for (int Index = 0; Index <= Manager->Count; Index++)    {      TThemeTabSheet * TabSheet;      if (Index >= SessionsPageControl->PageCount)      {        TabSheet = new TThemeTabSheet(SessionsPageControl);        TabSheet->PageControl = SessionsPageControl;      }      else      {        TabSheet = SessionsPageControl->Pages[Index];      }      bool IsSessionTab = (Index < Manager->Count);      if (IsSessionTab)      {        TTerminal * Terminal = Manager->Sessions[Index];        TabSheet->Tag = reinterpret_cast<int>(Terminal);        TabSheet->CaptionTruncation = WinConfiguration->SessionTabCaptionTruncation ? tttEllipsis : tttNone;        UpdateSessionTab(TabSheet);      }      else      {        TabSheet->Tag = 0; // not really needed        TabSheet->Shadowed = false;        TabSheet->Button = SupportsLocalBrowser() ? ttbDropDown : ttbNone;        TabSheet->CaptionTruncation = GetNewTabTabCaptionTruncation();        // We know that we are at the last page, otherwise we could not call this (it assumes that new session tab is the last one)        UpdateNewTabTab();      }    }    // Prevent flicker on the right side where scrolling buttons would be, unless really needed    if (ForceTruncationUpdate || (SessionsPageControl->TotalTabsWidth() != PrevTabsWidth))    {      SessionsPageControl->UpdateTabsCaptionTruncation();    }  }  __finally  {    SessionsPageControl->UnlockDrawing();  }  SessionsPageControl->ActivePageIndex = ActiveSessionIndex;}//---------------------------------------------------------------------------TThemeTabCaptionTruncation TCustomScpExplorerForm::GetNewTabTabCaptionTruncation(){  return WinConfiguration->SessionTabCaptionTruncation ? tttNoText : tttNone;}//---------------------------------------------------------------------------UnicodeString TCustomScpExplorerForm::GetNewTabTabCaption(){  return StripHotkey(StripTrailingPunctuation(NonVisualDataModule->NewTabAction->Caption));}//---------------------------------------------------------------------------TThemeTabSheet * TCustomScpExplorerForm::GetNewTabTab(){  return SessionsPageControl->Pages[SessionsPageControl->PageCount - 1];}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateNewTabTab(){  TThemeTabSheet * TabSheet = GetNewTabTab();  UnicodeString TabCaption;  if (WinConfiguration->SelectiveToolbarText)  {    TabCaption = GetNewTabTabCaption();  }  TabSheet->BaseCaption = TabCaption;  TabSheet->ImageIndex = GetNewTabTabImageIndex(osCurrent);}//---------------------------------------------------------------------------TManagedTerminal * __fastcall TCustomScpExplorerForm::GetSessionTabSession(TTabSheet * TabSheet){  return reinterpret_cast<TManagedTerminal *>(TabSheet->Tag);}//---------------------------------------------------------------------------UnicodeString TCustomScpExplorerForm::GetLocalBrowserSessionTitle(TManagedTerminal *){  DebugFail();  return UnicodeString();}//---------------------------------------------------------------------------void TCustomScpExplorerForm::UpdateSessionTab(TThemeTabSheet * TabSheet){  if (DebugAlwaysTrue(TabSheet != NULL))  {    TManagedTerminal * ASession = GetSessionTabSession(TabSheet);    if (DebugAlwaysTrue(ASession != NULL))    {      TColor Color = (ASession == Terminal) ? FSessionColor : ASession->StateData->Color;      if (ASession->LocalBrowser)      {        TabSheet->ImageIndex = FLocalBrowserTabImageIndex;      }      else      {        TabSheet->ImageIndex = AddSessionColor(Color);      }      TTerminalManager * Manager = TTerminalManager::Instance();      TabSheet->Shadowed = !ASession->Active && !ASession->LocalBrowser;      TabSheet->Button = CanCloseSession(ASession) ? ttbClose : ttbNone;      TabSheet->BaseCaption = Manager->GetSessionTitle(ASession, true);    }  }}//---------------------------------------------------------------------------bool TCustomScpExplorerForm::CanCloseSession(TManagedTerminal * Session){  return !Session->LocalBrowser || (TTerminalManager::Instance()->Count > 1);}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::SessionTabSwitched(){  DebugAssert(SessionsPageControl->ActivePage != NULL);  TManagedTerminal * Session = GetSessionTabSession(SessionsPageControl->ActivePage);  bool Result = (Session != NULL);  if (Result)  {    TTerminalManager::Instance()->ActiveSession = Session;  }  else  {    try    {      NewTab();    }    __finally    {      SessionListChanged();    }    FSessionsPageControlNewTabTime = Now();  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsPageControlChange(TObject * /*Sender*/){  TWindowLock Lock(this);  SessionTabSwitched();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TransferListChange(TObject * Sender){  TTBXStringList * TransferList = dynamic_cast<TTBXStringList *>(Sender);  DebugAssert(TransferList != NULL);  UnicodeString Name;  if (TransferList->ItemIndex <= 0)  {    Name = L"";  }  else  {    Name = GUIConfiguration->CopyParamList->Names[TransferList->ItemIndex - 1];  }  if (FCopyParamAutoSelected.IsEmpty())  {    // if previous preset was not autoselected, make new preset the "default"    FCopyParamDefault = Name;  }  GUIConfiguration->CopyParamCurrent = Name;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateTransferLabel(){  // sanity check  bool ExistingPreset =    (FTransferListHoverIndex >= 0) &&    (FTransferListHoverIndex < 1 + GUIConfiguration->CopyParamList->Count);  DebugAssert(ExistingPreset);  if (ExistingPreset)  {    HDC DC = GetDC(0);    TCanvas * Canvas = new TCanvas();    try    {      Canvas->Handle = DC;      Canvas->Font = GetToolbarFont(this);      UnicodeString Name;      if (FTransferListHoverIndex == 0)      {        Name = L"";      }      else      {        Name = GUIConfiguration->CopyParamList->Names[FTransferListHoverIndex - 1];      }      TTBXLabelItem * TransferLabel = dynamic_cast<TTBXLabelItem*>(        static_cast<TComponent*>(GetComponent(fcTransferLabel)));      TTBXStringList * TransferList = dynamic_cast<TTBXStringList*>(        static_cast<TObject*>(GetComponent(fcTransferList)));      UnicodeString InfoStr =        GUIConfiguration->CopyParamPreset[Name].          GetInfoStr(L"; ",            FLAGMASK(HasActiveTerminal(), Terminal->UsableCopyParamAttrs(0).General));      int MaxWidth = TransferList->MinWidth - (2 * TransferLabel->Margin) - ScaleByTextHeight(this, 10);      if (Canvas->TextExtent(InfoStr).cx > MaxWidth)      {        while (Canvas->TextExtent(InfoStr + Ellipsis).cx > MaxWidth)        {          InfoStr.SetLength(InfoStr.Length() - 1);        }        InfoStr += Ellipsis;      }      // UpdateCaption does not cause invalidation of whole submenu, while      // setting Caption property does.      // also it probably does not resize the label, even if necessary      // (we do not want that anyway)      TransferLabel->UpdateCaption(InfoStr);    }    __finally    {      Canvas->Handle = NULL;      ReleaseDC(0, DC);      delete Canvas;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TransferListDrawItem(  TTBXCustomList * /*Sender*/, TCanvas * /*ACanvas*/, const TRect & /*ARect*/,  int /*AIndex*/, int AHoverIndex, bool & /*DrawDefault*/){  if (FTransferListHoverIndex != AHoverIndex)  {    FTransferListHoverIndex = AHoverIndex;    UpdateTransferLabel();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::WMAppCommand(TMessage & Message){  int Command  = GET_APPCOMMAND_LPARAM(Message.LParam);  TShiftState Shift = KeyDataToShiftState(GET_KEYSTATE_LPARAM(Message.LParam));  if ((Shift * (TShiftState() << ssShift << ssAlt << ssCtrl)).Empty())  {    if (Command == APPCOMMAND_BROWSER_FAVORITES)    {      if (!NonVisualDataModule->Busy)      {        OpenDirectory(GetSide(osCurrent));      }      Message.Result = 1;    }    else    {      TForm::Dispatch(&Message);    }  }  else  {    TForm::Dispatch(&Message);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CMDialogChar(TMessage & AMessage){  TCMDialogChar & Message = reinterpret_cast<TCMDialogChar &>(AMessage);  if ((FIgnoreNextDialogChar != 0) &&      (towupper(Message.CharCode) == towupper(FIgnoreNextDialogChar)))  {    Message.Result = 1;  }  else  {    TForm::Dispatch(&Message);  }  FIgnoreNextDialogChar = 0;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::WMSysCommand(TMessage & Message){  // The four low-order bits are used internally by Windows  unsigned int Cmd = (Message.WParam & 0xFFF0);  // SC_RESTORE, SC_MAXIMIZE, SC_MINIMIZE - buttons on windows title  // SC_DEFAULT - double click on windows title (does not work, at least on WinXP)  // 61730 - restore thru double click - undocumented  // 61490 - maximize thru double click - undocumented  if ((Cmd == SC_RESTORE) || (Cmd == SC_MAXIMIZE) ||      (Cmd == SC_MINIMIZE) || (Cmd == SC_DEFAULT))  {    SysResizing(Cmd);  }  TForm::Dispatch(&Message);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::WMQueryEndSession(TMessage & Message){  AppLog(L"Windows session end query");  // We were actually never able to make ENDSESSION_CRITICAL happen.  // Also there no point returning TRUE as we are not able to  // handle the abrupt termination caused by subsequent WM_ENDSESSION cleanly.  // Hence the process termination might be safer :)  if ((Message.LParam != ENDSESSION_CRITICAL) &&      (((FQueue != NULL) && !FQueue->IsEmpty) || (FProgressForm != NULL)))  {    Message.Result = FALSE;  }  else  {    Message.Result = TRUE;  }  // Do not call default handling as that triggers OnCloseQuery,  // where our implementation will popup confirmation dialogs, what we do not want,  // as per Vista guidelines:  // https://learn.microsoft.com/en-us/windows/win32/shutdown/shutting-down}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::WMEndSession(TWMEndSession & Message){  AppLog(L"Windows session end");  if (Message.EndSession && IsApplicationMinimized())  {    // WORKAROUND    // TApplication.WndProc() calls Application.Terminate() before Halt(),    // when it receives WM_ENDSESSION,    // but that sometimes (particularly when application is minimized) cause crashes.    // Crash popups message that blocks log off.    // Obviously application cannot shutdown cleanly after WM_ENDSESSION,    // so we call ExitProcess() immediately, not even trying to cleanup.    // It still causes beep, so there's likely some popup, but it does not block    // log off.    ExitProcess(0);  }  TForm::Dispatch(&Message);}#ifdef _DEBUG//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::WMWindowPosChanged(TWMWindowPosMsg & Message){  TForm::Dispatch(&Message);}#endif//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SysResizing(unsigned int /*Cmd*/){}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoShow(){  // Called from TCustomScpExplorerForm::CMShowingChanged  // only now are the controls resized finally, so the size constraints  // will not conflict with possibly very small window size  RestoreFormParams();  // This indicates that the form was rescaled after parameters were loaded and  // as most probably the parameters were actually saved with the current form scaling  // (windows was the last time likely closed on the same monitor, where it is starting now),  // rescaling happened twice already. Reload the parameters, as now they likely won't need any scaling  // and no rounding problems will occur.  // See also RestoreForm.  // (we should be safe to call RestoreParams unconditionally)  if (PixelsPerInch != Screen->PixelsPerInch)  {    RestoreParams();  }  FixControlsPlacement();  if (Position == poDefaultPosOnly)  {    CutFormToDesktop(this);  }  TForm::DoShow();  FSessionsDragDropFilesEx->DragDropControl = SessionsPageControl;  FQueueDragDropFilesEx->DragDropControl = QueueView3;  // This was previously in NeedSession, where other related code is.  // But that is called from CMShowingChanged, when the window is already visible and the local-local window state  // unpleasantly shows briefly.  if ((ManagedSession == NULL) &&      !WinConfiguration->ShowLoginWhenNoSession &&      WinConfiguration->AutoSaveWorkspace && !WinConfiguration->AutoWorkspace.IsEmpty() &&      // This detects if workspace was saved the last time the main widow was closed      SameText(WinConfiguration->LastStoredSession, WinConfiguration->AutoWorkspace))  {    DoOpenFolderOrWorkspace(WinConfiguration->AutoWorkspace, false, true);    Configuration->Usage->Inc(L"OpenedWorkspacesAuto");  }  // Before main window displays  if (ManagedSession == NULL)  {    StartingWithoutSession();  }  UpdatePixelsPerInchMainWindowCounter();  FShowing = true;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdatePixelsPerInchMainWindowCounter(){  Configuration->Usage->Set(L"PixelsPerInchMainWindow", PixelsPerInch);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::StartingWithoutSession(){  SessionListChanged();  InitStatusBar();  UpdateControls();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::PopupTrayBalloon(TTerminal * Terminal,  const UnicodeString & Str, TQueryType Type, Exception * E, unsigned int Seconds,  TNotifyEvent OnBalloonClick, TObject * UserData){  bool Do;  UnicodeString Message;  if (E == NULL)  {    Message = Str;    Do = true;  }  else  {    Do = ExceptionMessage(E, Message);  }  if (Do && WinConfiguration->BalloonNotifications)  {    UnicodeString Title;    if ((Terminal == NULL) && (Type == qtInformation) && ExtractMainInstructions(Message, Title))    {      Message = TrimLeft(Message);    }    else    {      Message = UnformatMessage(Message);      const ResourceString * Captions[] = { &_SMsgDlgConfirm, &_SMsgDlgWarning,        &_SMsgDlgError, &_SMsgDlgInformation, NULL };      Title = LoadResourceString(Captions[Type]);      if (Terminal != NULL)      {        TManagedTerminal * Session = DebugNotNull(dynamic_cast<TManagedTerminal *>(Terminal->PrimaryTerminal));        Title = TTerminalManager::Instance()->GetSessionTitle(Session, true) + TitleSeparator + Title;      }    }    if (Seconds == 0)    {      Seconds = WinConfiguration->NotificationsTimeout;    }    FTrayIcon->PopupBalloon(Title, Message, Type, Seconds * MSecsPerSec, OnBalloonClick, UserData);  }}//---------------------------------------------------------------------------unsigned int __fastcall TCustomScpExplorerForm::MoreMessageDialog(const UnicodeString Message,    TStrings * MoreMessages, TQueryType Type, unsigned int Answers,    UnicodeString HelpKeyword, const TMessageParams * Params,    TTerminal * Terminal){  if (((WinConfiguration->ContinueOnError && (FErrorList != NULL)) ||       (FOnFeedSynchronizeError != NULL)) &&      (Params != NULL) && (Params->Params & mpAllowContinueOnError) )  {    if (FOnFeedSynchronizeError != NULL)    {      FOnFeedSynchronizeError(Message, MoreMessages, Type, HelpKeyword);    }    else    {      DebugAssert(FErrorList != NULL);      TStringList * MoreMessagesCopy = NULL;      if (MoreMessages)      {        MoreMessagesCopy = new TStringList();        MoreMessagesCopy->Assign(MoreMessages);      }      FErrorList->AddObject(Message, MoreMessagesCopy);    }    PopupTrayBalloon(Terminal, Message, Type);    return ContinueAnswer(Answers);  }  else  {    bool UseBalloon = FTrayIcon->Visible;    if (UseBalloon)    {      PopupTrayBalloon(Terminal, Message, Type);    }    unsigned int Result;    try    {      Result = ::MoreMessageDialog(Message, MoreMessages, Type, Answers, HelpKeyword, Params);    }    __finally    {      // cancel only balloon we popped up, otherwise we may cancel notification      // balloon that was there before the message dialog      // (such as "dd confirmation opt in balloon)      if (UseBalloon)      {        FTrayIcon->CancelBalloon();      }    }    return Result;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ShowExtendedException(  TTerminal * Terminal, Exception * E){  if (FTrayIcon->Visible)  {    PopupTrayBalloon(Terminal, L"", qtError, E);  }  // particularly prevent opening new session from jump list,  // while exception is shown  NonVisualDataModule->StartBusy();  try  {    ShowExtendedExceptionEx(Terminal, E);  }  __finally  {    NonVisualDataModule->EndBusy();    FTrayIcon->CancelBalloon();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionReady(){  InitStatusBar();  // cannot rely on active page being page for active terminal,  // as it can happen that active page is the "new session" page  // (e.g. when reconnecting active terminal, while login dialog  // invoked from "new session" page is modal)  int ActiveSessionIndex = TTerminalManager::Instance()->ActiveSessionIndex;  UpdateSessionTab(SessionsPageControl->Pages[ActiveSessionIndex]);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::InactiveTerminalException(  TTerminal * Terminal, Exception * E){  Notify(Terminal, L"", qtError, false, NULL, NULL, E);  if (!Terminal->Active)  {    int Index = TTerminalManager::Instance()->IndexOf(Terminal);    if (DebugAlwaysTrue((Index >= 0) && (Index < SessionsPageControl->PageCount)))    {      UpdateSessionTab(SessionsPageControl->Pages[Index]);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::Notify(TTerminal * Terminal,  UnicodeString Message, TQueryType Type,  bool Important, TNotifyEvent OnClick, TObject * UserData, Exception * E){  if ((E == NULL) ||      ExceptionMessage(E, Message))  {    unsigned int Seconds = WinConfiguration->NotificationsTimeout;    if (Important)    {      Seconds *= 5;    }    UnicodeString NoteMessage(UnformatMessage(Message));    if (Terminal != NULL)    {      TManagedTerminal * Session = DebugNotNull(dynamic_cast<TManagedTerminal *>(Terminal));      NoteMessage = FORMAT(L"%s: %s",        (TTerminalManager::Instance()->GetSessionTitle(Session, true), NoteMessage));    }    if (WinConfiguration->BalloonNotifications)    {      AddNote(NoteMessage);      PopupTrayBalloon(Terminal, Message, Type, NULL, Seconds, OnClick, UserData);    }    else    {      FlashOnBackground();      PostNote(NoteMessage, Seconds, OnClick, UserData);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueEmptyNoteClicked(TObject * Sender){  RestoreApp();  TTerminalNoteData * TerminalNoteData = dynamic_cast<TTerminalNoteData *>(Sender);  if (DebugAlwaysTrue(TerminalNoteData != NULL) &&      !NonVisualDataModule->Busy)  {    TManagedTerminal * Terminal = TerminalNoteData->Terminal;    TTerminalManager::Instance()->ActiveSession = Terminal;    if (!ComponentVisible[fcQueueView])    {      ToggleQueueVisibility();      GoToQueue();    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueEvent(TManagedTerminal * ATerminal,  TTerminalQueue * /*Queue*/, TQueueEvent Event){  UnicodeString Message;  TNotifyEvent OnClick = NULL;  TObject * UserData = NULL;  bool QueueInvisible = !ComponentVisible[fcQueueView] || IsApplicationMinimized();  switch (Event)  {    case qeEmptyButMonitored:      if ((ATerminal != Terminal) || QueueInvisible)      {        Message = LoadStr(BALLOON_QUEUE_EMPTY);        OnClick = QueueEmptyNoteClicked;        TTerminalNoteData * TerminalNoteData = new TTerminalNoteData();        TerminalNoteData->Terminal = ATerminal;        UserData = TerminalNoteData;      }      break;    case qeEmpty:      OperationComplete(ATerminal->QueueOperationStart);      break;    case qePendingUserAction:      if ((ATerminal != Terminal) ||          (QueueInvisible && !IsQueueAutoPopup()))      {        Message = LoadStr(BALLOON_QUEUE_USER_ACTION);      }      break;    default:      DebugFail();  }  if (!Message.IsEmpty())  {    Notify(ATerminal, Message, qtInformation, false, OnClick, UserData);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDDCreateDragFileList(  TObject * /*Sender*/, TFileList * FileList, bool & Created){  if (FDDExtMapFile != NULL)  {    CloseHandle(FDDExtMapFile);    FDDExtMapFile = NULL;  }  if (WinConfiguration->DDFakeFile)  {    DDFakeFileInitDrag(FileList, Created);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DDFakeCreated(TObject * /*Sender*/, const UnicodeString FileName){  if (DebugAlwaysTrue(!FDragFakeDirectory.IsEmpty()) &&      SameText(ExtractFileName(FileName), ExtractFileName(FDragFakeDirectory)))  {    FFakeFileDropTarget = FileName;  }}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::CreateFakeTransferDirectory(){  UnicodeString Result = ExcludeTrailingBackslash(WinConfiguration->TemporaryDir());  if (!ForceDirectories(ApiPath(Result)))  {    throw Exception(FMTLOAD(CREATE_TEMP_DIR_ERROR, (Result)));  }  FileSetAttr(ApiPath(Result), faHidden);  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DDFakeFileInitDrag(TFileList * FileList,  bool & Created){  FFakeFileDropTarget = UnicodeString();  FDragFakeDirectory = CreateFakeTransferDirectory();  FileList->AddItem(NULL, FDragFakeDirectory);  Created = true;  if (!WinConfiguration->IsDDExtRunning() || WinConfiguration->IsDDExtBroken())  {    FDragFakeMonitors = StartCreationDirectoryMonitorsOnEachDrive(FILE_NOTIFY_CHANGE_DIR_NAME, DDFakeCreated);  }  FDDExtMapFile = CreateFileMappingA((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE,    0, sizeof(TDragExtCommStruct), AnsiString(DRAG_EXT_MAPPING).c_str());  {    TMutexGuard Guard(FDDExtMutex, DRAGEXT_MUTEX_RELEASE_TIMEOUT);    TDragExtCommStruct* CommStruct;    CommStruct = static_cast<TDragExtCommStruct*>(MapViewOfFile(FDDExtMapFile,      FILE_MAP_ALL_ACCESS, 0, 0, 0));    DebugAssert(CommStruct != NULL);    CommStruct->Version = TDragExtCommStruct::CurrentVersion;    CommStruct->Dragging = true;    wcsncpy(CommStruct->DropDest, FDragFakeDirectory.c_str(),      LENOF(CommStruct->DropDest));    NULL_TERMINATE(CommStruct->DropDest);    UnmapViewOfFile(CommStruct);  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::RemoteFileControlFileOperation(  TObject * Sender, TFileOperation Operation, bool NoConfirmation, void * Param){  bool Result;  DebugAssert(!IsLocalBrowserMode());  if (Sender == RemoteDirView)  {    Result = ExecuteFileOperation(Operation, osRemote, true, NoConfirmation, Param);  }  else  {    DebugAssert(Sender == RemoteDriveView);    TStrings * FileList = RemoteDriveView->DragFileList();    try    {      Result = ExecuteFileOperation(Operation, osRemote, FileList, NoConfirmation, Param);    }    __finally    {      delete FileList;    }  }  if (FDDTargetControl == RemoteDriveView)  {    RemoteDriveView->UpdateDropTarget();  }  // foRemoteMove happens when file/dir is dragged within the remote tree view  // or from tree view to dir view.  // foMove happens when file/dir is dragged from remote tree view outside of  // application via dragex  if (((Operation == foRemoteMove) || (Operation == foMove)) &&      (DropSourceControl == RemoteDriveView))  {    RemoteDriveView->UpdateDropSource();  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDDEnd(TObject * Sender){  DebugAssert(!IsLocalBrowserMode());  // This also handles drops of remote files to queue.  // Drops of local files (uploads) are handled in QueueDDProcessDropped.  SAFE_DESTROY(FDDFileList);  if (!FFakeFileDropTarget.IsEmpty())  {    RemoveDir(ApiPath(FFakeFileDropTarget));  }  if ((FDDExtMapFile != NULL) || (FDDTargetControl == QueueView3))  {    try    {      TDragResult DDResult = (Sender == RemoteDirView) ?        RemoteDirView->LastDDResult : RemoteDriveView->LastDDResult;      // Focus is moved to the target application,      // but as we are going to present the UI, we need to steal the focus back.      // This most likely won't work though (windows does not allow application      // to steal focus most of the time)      Application->BringToFront();      // On older version of Windows we never got drMove here, see also comment below.      // On Windows 10, we get the "move".      if ((DDResult == drCopy) || (DDResult == drMove) || (DDResult == drInvalid))      {        UnicodeString TargetDirectory;        TFileOperation Operation;        // drInvalid may mean drMove, see comment below        switch (DDResult)        {          case drCopy:            Operation = foCopy;            break;          case drMove:            Operation = foMove;            break;          default:            DebugFail();          case drInvalid:            // prefer "copy" for safety            Operation = FLAGSET(FLastDropEffect, DROPEFFECT_MOVE) ? foMove : foCopy;            break;        }        TTransferOperationParam Param;        UnicodeString CounterName;        bool ForceQueue;        if (!DDGetTarget(Param.TargetDirectory, ForceQueue, CounterName))        {          // we get drInvalid both if d&d was intercepted by ddext,          // and when users drops on no-drop location.          // we tell the difference by existence of response from ddext,          // so we ignore absence of response in this case          if (DDResult != drInvalid)          {            // here we know that the extension is installed,            // as it is checked as soon as drag&drop starts from            // RemoteFileControlDDCreateDragFileList            Configuration->Usage->Inc(L"DownloadsDragDropExternalExtTargetUnknown");            if (!WinConfiguration->DDExtInstalled || WinConfiguration->IsDDExtBroken())            {              throw ExtException(NULL, LoadStr(DD_TARGET_UNKNOWN), HELP_DD_TARGET_UNKNOWN);            }            else            {              throw ExtException(NULL, LoadStr(DRAGEXT_TARGET_UNKNOWN2), HELP_DRAGEXT_TARGET_UNKNOWN);            }          }        }        else        {          // download using fake file          Param.Temp = false;          Param.DragDrop = true;          if (ForceQueue)          {            Param.Queue = asOn;          }          if (Sender == RemoteDirView)          {            Param.Options = FLAGMASK(SelectedAllFilesInDirView(RemoteDirView), coAllFiles);          }          if (RemoteFileControlFileOperation(Sender, Operation,                (WinConfiguration->DDTransferConfirmation == asOff), &Param))          {            Configuration->Usage->Inc(CounterName);          }        }      }    }    __finally    {      CloseHandle(FDDExtMapFile);      FDDExtMapFile = NULL;      delete FDragFakeMonitors;      FDragFakeMonitors = NULL;      RemoveDir(ApiPath(FDragFakeDirectory));      FDragFakeDirectory = L"";      FFakeFileDropTarget = UnicodeString();    }  }  if (FDragDropSshTerminate.get() != NULL)  {    FDragDropSshTerminate->Rethrow();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDDGiveFeedback(  TObject * /*Sender*/, int dwEffect, HRESULT & /*Result*/){  // Remember drop effect so we know (when user drops files), if we copy or move  FLastDropEffect = dwEffect;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::DDGetTarget(  UnicodeString & Directory, bool & ForceQueue, UnicodeString & CounterName){  bool Result;  if (FDDTargetControl == QueueView3)  {    Directory = DefaultDownloadTargetDirectory();    Result = true;    CounterName = L"DownloadsDragDropQueue";    ForceQueue = true;  }  else if (!FFakeFileDropTarget.IsEmpty())  {    Directory = ExcludeTrailingBackslash(ExtractFilePath(FFakeFileDropTarget));    Result = true;    ForceQueue = false;    CounterName = L"DownloadsDragDropFakeFile";  }  else  {    ForceQueue = false;    Enabled = false;    try    {      int Timer = 0;      Result = false;      while (!Result && (Timer < WinConfiguration->DDExtTimeout))      {        {          TMutexGuard Guard(FDDExtMutex, DRAGEXT_MUTEX_RELEASE_TIMEOUT);          TDragExtCommStruct* CommStruct;          CommStruct = static_cast<TDragExtCommStruct*>(MapViewOfFile(FDDExtMapFile,            FILE_MAP_ALL_ACCESS, 0, 0, 0));          DebugAssert(CommStruct != NULL);          Result = !CommStruct->Dragging;          if (Result)          {            Directory = ExtractFilePath(CommStruct->DropDest);            CounterName = L"DownloadsDragDropExternalExt";          }          UnmapViewOfFile(CommStruct);        }        if (!Result)        {          Sleep(50);          Timer += 50;          Application->ProcessMessages();        }      }    }    __finally    {      Enabled = true;    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AddDelayedDirectoryDeletion(  const UnicodeString TempDir, int SecDelay){  TDateTime Alarm = IncSecond(Now(), SecDelay);  FDelayedDeletionList->AddObject(TempDir, reinterpret_cast<TObject*>(Alarm.FileDate()));  if (FDelayedDeletionTimer == NULL)  {    DebugAssert(HandleAllocated());    FDelayedDeletionTimer = new TTimer(this);    FDelayedDeletionTimer->Interval = 10000;    FDelayedDeletionTimer->OnTimer = DoDelayedDeletion;  }  else  {    FDelayedDeletionTimer->Enabled = true;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoDelayedDeletion(TObject * Sender){  DebugAssert(FDelayedDeletionList != NULL);  TDateTime N = Now();  TDateTime Alert;  UnicodeString Directory;  for (int Index = FDelayedDeletionList->Count-1; Index >= 0; Index--)  {    Alert = FileDateToDateTime(reinterpret_cast<int>(FDelayedDeletionList->Objects[Index]));    if ((N >= Alert) || (Sender == NULL))    {      Directory = FDelayedDeletionList->Strings[Index];      if (RecursiveDeleteFile(ExcludeTrailingBackslash(Directory)))      {        FDelayedDeletionList->Delete(Index);      }    }  }  if (FDelayedDeletionList->Count == 0)  {    FDelayedDeletionTimer->Enabled = false;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDDTargetDrop(){  DebugAssert(!IsLocalBrowserMode());  if (IsFileControl(FDDTargetControl, osRemote) ||      (FDDTargetControl == SessionsPageControl))  {    TManagedTerminal * TargetTerminal = NULL;    TFileOperation Operation = foNone;    if (FDDTargetControl == SessionsPageControl)    {      TPoint Point = SessionsPageControl->ScreenToClient(Mouse->CursorPos);      int Index = SessionsPageControl->IndexOfTabAt(Point.X, Point.Y);      // do not allow dropping on local-local, disconnected and the "+" tab (see also SessionsDDProcessDropped)      TargetTerminal = GetSessionTabSession(SessionsPageControl->Pages[Index]);      if (IsActiveTerminal(TargetTerminal) && DebugAlwaysTrue(!TargetTerminal->LocalBrowser))      {        if ((FLastDropEffect == DROPEFFECT_MOVE) &&            (TargetTerminal == TTerminalManager::Instance()->ActiveTerminal))        {          Operation = foRemoteMove;        }        else        {          Operation = foRemoteCopy;        }      }    }    else    {      if (FLastDropEffect == DROPEFFECT_MOVE)      {        Operation = foRemoteMove;      }      else if (FLastDropEffect == DROPEFFECT_COPY)      {        Operation = foRemoteCopy;      }    }    if (Operation != foNone)    {      RemoteFileControlFileOperation(DropSourceControl,        Operation, (WinConfiguration->DDTransferConfirmation == asOff), TargetTerminal);    }    // abort drag&drop    Abort();  }  else if ((FDDExtMapFile == NULL) && (FLastDropEffect != DROPEFFECT_NONE) &&           // Drops of remote files to queue are handled in RemoteFileControlDDEnd           (FDDTargetControl != QueueView3))  {    DebugAssert(!FDragTempDir.IsEmpty());    TTransferType Type;    UnicodeString TempDir = FDragTempDir;    // We clear FDragTempDir before calling    // just in case it fail (raises exception)    FDragTempDir = L"";    Type = (FLastDropEffect & DROPEFFECT_MOVE ? ttMove : Type = ttCopy);    TGUICopyParamType CopyParams = GUIConfiguration->CurrentCopyParam;    // empty directory parameter means temp directory -> don't display it!    UnicodeString TargetDir = L"";    int Options = 0;    if (!CopyParamDialog(tdToLocal, Type, true, FDDFileList,          TargetDir, CopyParams, (WinConfiguration->DDTransferConfirmation != asOff), true, Options))    {      Abort();    }    // TargetDir is set when dropped on local file control    // (this was workaround for legacy dirview event handling, now it should be    // made prettier)    if (TargetDir.IsEmpty())    {      TargetDir = TempDir;      if (ForceDirectories(ApiPath(TargetDir)))      {        DebugAssert(Terminal && !TargetDir.IsEmpty());        FPendingTempSpaceWarn = true;        try        {          FDragDropOperation = true;          int Params = cpTemporary |            (Type == ttMove ? cpDelete : 0);          DDDownload(FDDFileList, TargetDir, &CopyParams, Params);          Configuration->Usage->Inc(L"DownloadsDragDropExternalTemp");        }        __finally        {          FDragDropOperation = false;          FPendingTempSpaceWarn = false;          AddDelayedDirectoryDeletion(TargetDir, WinConfiguration->DDDeleteDelay);        }      }      else      {        throw Exception(FMTLOAD(CREATE_TEMP_DIR_ERROR, (TargetDir)));      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DDDownload(  TStrings * FilesToCopy, const UnicodeString & TargetDir, TCopyParamType * CopyParam, int Params){  DebugAssert(!IsLocalBrowserMode());  TAutoBatch AutoBatch(this);  CopyParam->IncludeFileMask.SetRoots(TargetDir, FilesToCopy);  UpdateCopyParamCounters(*CopyParam);  FMoveToQueue = false;  Terminal->CopyToLocal(FilesToCopy, TargetDir, CopyParam, Params, NULL);  if (FLAGSET(Params, cpDelete) && (DropSourceControl == RemoteDriveView))  {    RemoteDriveView->UpdateDropSource();  }}//---------------------------------------------------------------------------class TFakeDataObjectFilesEx : public TDataObjectFilesEx{public:  __fastcall TFakeDataObjectFilesEx(TFileList * AFileList, bool RenderPIDL,    bool RenderFilename) : TDataObjectFilesEx(AFileList, RenderPIDL, RenderFilename, true)  {  }  virtual bool __fastcall AllowData(const tagFORMATETC & FormatEtc)  {    return (FormatEtc.cfFormat == CF_HDROP) ? false :      TDataObjectFilesEx::AllowData(FormatEtc);  }};//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDDCreateDataObject(  TObject * Sender, TDataObject *& DataObject){  if (FDDExtMapFile != NULL)  {    TFileList * FileList = DragDropFiles(Sender)->FileList;    if (!FileList->RenderPIDLs() || !FileList->RenderNames())    {      Abort();    }    if (FileList->Count > 0)    {      TDataObjectFilesEx * FilesObject = new TFakeDataObjectFilesEx(FileList, true, true);      if (!FilesObject->IsValid(true, true))      {        FilesObject->_Release();      }      else      {        DataObject = FilesObject;      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::GoToCommandLine(){  DebugFail();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::GoToTree(){  ComponentVisible[fcRemoteTree] = true;  DriveView(osRemote)->SetFocus();}//---------------------------------------------------------------------------TStrings * __fastcall TCustomScpExplorerForm::PanelExport(TOperationSide Side,  TPanelExport Export){  TCustomDirView * DirView = this->DirView(Side);  std::unique_ptr<TStrings> ExportData(new TStringList());  switch (Export)  {    case pePath:      ExportData->Add(DirView->PathName);      break;    case peFileList:    case peFullFileList:      {        bool FullPath = (Export == peFullFileList);        DirView->CreateFileList(false, FullPath, ExportData.get());        for (int Index = 0; Index < ExportData->Count; Index++)        {          if (ExportData->Strings[Index].Pos(L" ") > 0)          {            ExportData->Strings[Index] = FORMAT(L"\"%s\"", (ExportData->Strings[Index]));          }        }      }      break;    default:      DebugFail();  }  return ExportData.release();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::PanelExport(TOperationSide Side,  TPanelExport Export, TPanelExportDestination Destination){  std::unique_ptr<TStrings> ExportData(PanelExport(Side, Export));  PanelExportStore(Side, Export, Destination, ExportData.get());}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::PanelExportStore(TOperationSide /*Side*/,  TPanelExport /*Export*/, TPanelExportDestination Destination,  TStrings * ExportData){  if (Destination == pedClipboard)  {    TInstantOperationVisualizer Visualizer;    CopyToClipboard(ExportData);  }  else  {    DebugFail();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::Filter(TOperationSide Side){  TCustomDirView * DirView = this->DirView(Side);  UnicodeString Mask = DirView->Mask;  if (DoFilterMaskDialog(DirView, Mask))  {    DirView->Mask = TFileMasks::NormalizeMask(Mask);    Configuration->Usage->Inc(L"Filters");  }}//---------------------------------------------------------------------------TQueueOperation __fastcall TCustomScpExplorerForm::DefaultQueueOperation(){  return FQueueController->DefaultOperation();}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::AllowQueueOperation(  TQueueOperation Operation, void ** Param){  switch (Operation)  {    case qoPreferences:      return true;    case qoGoTo:      return ComponentVisible[fcQueueView] && QueueView3->Enabled;    case qoOnceEmpty:      return IsAnythingQueued();    default:      return FQueueController->AllowOperation(Operation, Param);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::GoToQueue(){  if (DebugAlwaysTrue(QueueView3->Visible))  {    QueueView3->SetFocus();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ExecuteQueueOperation(  TQueueOperation Operation, void * Param){  if (Operation == qoGoTo)  {    GoToQueue();  }  else if (Operation == qoPreferences)  {    PreferencesDialog(pmQueue);  }  else  {    FQueueController->ExecuteOperation(Operation, Param);  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::GetQueueEnabled(){  return (Queue != NULL) && Queue->Enabled;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ToggleQueueEnabled(){  DebugAssert(Queue != NULL);  if (Queue != NULL)  {    Queue->Enabled = !Queue->Enabled;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3ContextPopup(  TObject * /*Sender*/, TPoint & /*MousePos*/, bool & /*Handled*/){  FQueueActedItem = QueueView3->ItemFocused;}//---------------------------------------------------------------------------/*virtual*/ int __fastcall TCustomScpExplorerForm::GetStaticComponentsHeight(){  return TopDock->Height + (MessageDock->Visible ? MessageDock->Height : 0) + QueueSplitter->Height;}//---------------------------------------------------------------------------int __fastcall TCustomScpExplorerForm::GetStaticQueuePanelComponentsHeight(){  return    (QueueFileListSplitter->Visible ? QueueFileListSplitter->Height : 0) +    (QueueDock->Visible ? QueueDock->Height : 0) +    (QueueLabel->Visible ? QueueLabel->Height : 0);}//---------------------------------------------------------------------------int __fastcall TCustomScpExplorerForm::GetMinQueueViewHeight(){  return ScaleByTextHeight(this, 48);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueSplitterCanResize(  TObject * /*Sender*/, int & NewSize, bool & Accept){  // when queue is hidden by double-clicking splitter, stray attempt to  // resize the panel with strange value arrives, make sure it is ignored  if (ComponentVisible[fcQueueView])  {    int MaxHeightLimit = ClientHeight - GetStaticComponentsHeight() - RemotePanel->Constraints->MinHeight;    if (NewSize > MaxHeightLimit)    {      NewSize = MaxHeightLimit;    }    int MinHeightLimit =      GetStaticQueuePanelComponentsHeight() +      (QueueFileList->Visible ? QueueFileList->Height : 0) +      GetMinQueueViewHeight();    if (NewSize < MinHeightLimit)    {      NewSize = MinHeightLimit;    }  }  else  {    Accept = false;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueFileListSplitterCanResize(TObject *, int & NewSize, bool &){  int TotalHeight = GetStaticQueuePanelComponentsHeight() + NewSize;  int QueueViewHeight = QueuePanel->ClientHeight - TotalHeight;  if (QueueViewHeight < GetMinQueueViewHeight())  {    NewSize -= (GetMinQueueViewHeight() - QueueViewHeight);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3StartDrag(TObject * /*Sender*/,  TDragObject *& /*DragObject*/){  FQueueActedItem = QueueView3->ItemFocused;  FQueueScrollOnDragOver->StartDrag();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3EndDrag(  TObject *, TObject * DebugUsedArg(Target), int DebugUsedArg(X), int DebugUsedArg(Y)){  FQueueScrollOnDragOver->EndDrag();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3DragOver(TObject * /*Sender*/,  TObject * Source, int X, int Y, TDragState /*State*/, bool & Accept){  Accept = true;  if (Source == QueueView3)  {    TListItem * DropTarget = QueueView3->GetItemAt(X, Y);    Accept = (DropTarget != NULL) && (FQueueActedItem != NULL);    if (Accept)    {      TQueueItemProxy * QueueItem;      TQueueItemProxy * DestQueueItem;      QueueItem = static_cast<TQueueItemProxy *>(FQueueActedItem->Data);      DestQueueItem = static_cast<TQueueItemProxy *>(DropTarget->Data);      Accept = (QueueItem != DestQueueItem) &&        (QueueItem->Status == TQueueItem::qsPending) &&        (DestQueueItem->Status == TQueueItem::qsPending);    }    FQueueScrollOnDragOver->DragOver(TPoint(X, Y));  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3DragDrop(TObject * /*Sender*/,  TObject * /*Source*/, int /*X*/, int /*Y*/){  if ((FQueueActedItem != NULL) && (QueueView3->DropTarget != NULL))  {    TQueueItemProxy * QueueItem;    TQueueItemProxy * DestQueueItem;    QueueItem = static_cast<TQueueItemProxy *>(FQueueActedItem->Data);    DestQueueItem = static_cast<TQueueItemProxy *>(QueueView3->DropTarget->Data);    QueueItem->Move(DestQueueItem);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3Enter(TObject * /*Sender*/){  if ((QueueView3->ItemFocused == NULL) &&      (QueueView3->Items->Count > 0))  {    QueueView3->ItemFocused = QueueView3->Items->Item[0];  }  QueueLabelUpdateStatus();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3Exit(TObject * /*Sender*/){  QueueLabelUpdateStatus();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueLabelUpdateStatus(){  QueueLabel->UpdateStatus();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3SelectItem(  TObject * /*Sender*/, TListItem * /*Item*/, bool Selected){  if (Selected)  {    NonVisualDataModule->UpdateNonVisibleActions();  }}//---------------------------------------------------------------------------TDragDropFilesEx * __fastcall TCustomScpExplorerForm::DragDropFiles(TObject * Sender){  TDragDropFilesEx * Result = NULL;  if (Sender == SessionsPageControl)  {    Result = FSessionsDragDropFilesEx;  }  else if (Sender == QueueView3)  {    Result = FQueueDragDropFilesEx;  }  else  {    TCustomDirView * DirView = dynamic_cast<TCustomDirView *>(Sender);    if (DirView != NULL)    {      Result = DirView->DragDropFilesEx;    }    else    {      TCustomDriveView * DriveView = dynamic_cast<TCustomDriveView *>(Sender);      if (DriveView != NULL)      {        Result = DriveView->DragDropFilesEx;      }    }  }  DebugAssert(Result != NULL);  return Result;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::SelectedAllFilesInDirView(TCustomDirView * DView){  return (DView->SelCount == DView->FilesCount);}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::DraggingAllFilesFromDirView(TOperationSide Side, TStrings * FileList){  return HasDirView[Side] && (DropSourceControl == DirView(Side)) && (FileList->Count == DirView(Side)->FilesCount);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDragDropFileOperation(  TObject * Sender, int Effect, UnicodeString TargetPath, bool ForceQueue, bool DragDrop){  DebugAssert(!IsLocalBrowserMode());  TFileOperation Operation;  switch (Effect)  {    case DROPEFFECT_MOVE:      Operation = foMove;      break;    case DROPEFFECT_COPY:    // occures on WinXP (reported by user)    default:      Operation = foCopy;      break;  };  TDragDropFilesEx * DragDropFilesEx = DragDropFiles(Sender);  // see a comment in TUnixDirView::PerformItemDragDropOperation  if (DragDropFilesEx->FileList->Count > 0)  {    TStrings * FileList = new TStringList();    try    {      for (int Index = 0; Index < DragDropFilesEx->FileList->Count; Index++)      {        FileList->Add(DragDropFilesEx->FileList->Items[Index]->Name);      }      FDragDropOperation = true;      TTransferOperationParam Param;      Param.TargetDirectory = TargetPath;      // upload, no temp dirs      Param.Temp = false;      Param.DragDrop = DragDrop;      Param.Options =        FLAGMASK(DraggingAllFilesFromDirView(osLocal, FileList), coAllFiles);      if (ForceQueue)      {        Param.Queue = asOn;      }      bool NoConfirmation = DragDrop ? (WinConfiguration->DDTransferConfirmation == asOff) : false;      if (ExecuteFileOperation(Operation, osLocal, FileList, NoConfirmation, &Param))      {        if (IsFileControl(DropSourceControl, osLocal))        {          Configuration->Usage->Inc(L"UploadsDragDropInternal");        }        else        {          Configuration->Usage->Inc(L"UploadsDragDropExternal");        }      }    }    __finally    {      FDragDropOperation = false;      delete FileList;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDDFileOperation(  TObject * Sender, int Effect, UnicodeString /*SourcePath*/,  UnicodeString TargetPath, bool Paste, bool & /*DoOperation*/){  RemoteFileControlDragDropFileOperation(Sender, Effect, TargetPath, false, !Paste);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileContolDDChooseEffect(  TObject * Sender, int grfKeyState, int & dwEffect){  DebugAssert(!IsLocalBrowserMode());  // if any drop effect is allowed at all (e.g. no drop to self and drop to parent)  if ((dwEffect != DROPEFFECT_NONE) &&      IsFileControl(DropSourceControl, osRemote))  {    // do not allow drop on remote panel (on free space, still allow drop on directories)    if ((Sender == RemoteDirView) && (DropSourceControl == RemoteDirView) &&        (RemoteDirView->DropTarget == NULL))    {      dwEffect = DROPEFFECT_NONE;    }    else    {      if (dwEffect == DROPEFFECT_COPY)      {        bool MoveCapable = Terminal->IsCapable[fcRemoteMove];        // currently we support copying always (at least via temporary directory);        // remove associated checks once this all proves stable and working        bool CopyCapable = true;        // if we do not support neither of operations, there's no discussion        if (!MoveCapable && !CopyCapable)        {          dwEffect = DROPEFFECT_NONE;        }        else        {          // The default effect inside remote panel is move,          // unless we do not support it, but support copy          if (FLAGCLEAR(grfKeyState, MK_CONTROL))          {            dwEffect = MoveCapable ? DROPEFFECT_MOVE : DROPEFFECT_COPY;          }          else          {            // with ctrl-down, we want copy unless it is not supported            dwEffect = CopyCapable ? DROPEFFECT_COPY : DROPEFFECT_NONE;          }        }      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDDDragFileName(  TObject * Sender, TRemoteFile * File, UnicodeString & FileName){  DebugAssert(!IsLocalBrowserMode());  if (FDDTotalSize >= 0)  {    if (File->IsDirectory)    {      FDDTotalSize = -1;    }    else    {      FDDTotalSize += File->Size;    }  }  DebugAssert(!FDragTempDir.IsEmpty());  // TODO: this is quite ineffective  // TODO: what if invalid character replacement is disabled?  FileName = FDragTempDir + GUIConfiguration->CurrentCopyParam.ValidLocalFileName(File->FileName);  UnicodeString TransferFileName;  if (Sender == RemoteDriveView)  {    TransferFileName = UnixExcludeTrailingBackslash(File->FullFileName);  }  else  {    TransferFileName = File->FileName;  }  FDDFileList->AddObject(TransferFileName, File);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDDDragDetect(  TObject * /*Sender*/, int /*grfKeyState*/, const TPoint & /*DetectStart*/,  const TPoint & /*Point*/, TDragDetectStatus /*DragStatus*/){  // sometimes we do not get DDEnd so the list is not released  SAFE_DESTROY(FDDFileList);  FDDFileList = new TStringList();  FDragTempDir = WinConfiguration->TemporaryDir();  FDDTotalSize = 0;  FDragDropSshTerminate.reset(NULL);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFileControlDDQueryContinueDrag(  TObject * /*Sender*/, LongBool /*FEscapePressed*/, int /*grfKeyState*/,  HRESULT & Result){  if (Result == DRAGDROP_S_DROP)  {    try    {      GlobalDragImageList->HideDragImage();      try      {        RemoteFileControlDDTargetDrop();      }      catch(ESshTerminate & E)      {        FDragDropSshTerminate.reset(E.Clone());      }    }    catch (Exception &E)    {      // If downloading fails we need to cancel drag&drop, otherwise      // Explorer shows error      // But by the way exception probably never reach this point as      // it's catched on way.      // Fatal exceptions get here (like when opening a secondary shell extension for file duplication fails).      Result = DRAGDROP_S_CANCEL;      ShowExtendedException(Terminal, &E);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewMatchMask(  TObject * /*Sender*/, UnicodeString FileName, bool Directory, __int64 Size,  TDateTime Modification, UnicodeString Masks, bool & Matches, bool AllowImplicitMatches){  TFileMasks::TParams MaskParams;  MaskParams.Size = Size;  MaskParams.Modification = Modification;  // this does not re-parse the mask if it is the same as the last time  FDirViewMatchMask = Masks;  bool ImplicitMatch;  Matches =    // Local and RecurseInclude parameters have no effect as there's no path.    // This should use potential MatchesFileName overload with ImplicitMatch argument.    FDirViewMatchMask.Matches(FileName, false, Directory, &MaskParams, true, ImplicitMatch) &&    (AllowImplicitMatches || !ImplicitMatch);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewGetOverlay(  TObject * Sender, TListItem * Item, WORD & Indexes){  TCustomDirView * DirView = reinterpret_cast<TCustomDirView *>(Sender);  if (GetPartialFileExtLen(DirView->ItemFileName(Item)) > 0)  {    Indexes |= oiPartial;  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanPasteToDirViewFromClipBoard(){  return    DirViewEnabled(osCurrent) &&    DirView(osCurrent)->CanPasteFromClipBoard();}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanPasteFromClipBoard(){  bool Result = false;  if (CanPasteToDirViewFromClipBoard())  {    Result = true;  }  else  {    UnicodeString ClipboardText;    if (NonEmptyTextFromClipboard(ClipboardText) &&        (ClipboardText.Pos(L"\n") == 0)) // it's already trimmed    {      if (StoredSessions->IsUrl(ClipboardText))      {        Result = true;      }      else      {        Result = DirViewEnabled(osCurrent);      }    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::PasteFromClipBoard(){  // Pasting to any local panel is handled in TScpCommanderForm::PasteFromClipBoard()  if (DoesClipboardContainOurFiles())  {    if (DebugAlwaysTrue(CanPasteToDirViewFromClipBoard()))    {      DebugAssert(!IsLocalBrowserMode());      TTerminalManager * Manager = TTerminalManager::Instance();      TTerminal * TargetTerminal = Manager->ActiveTerminal;      Manager->ActiveSession = FClipboardTerminal;      ExecuteFileOperation(foRemoteCopy, osRemote, FClipboardFileList.get(), false, TargetTerminal);    }  }  else if (CanPasteToDirViewFromClipBoard())  {    DirView(osCurrent)->PasteFromClipBoard();  }  else  {    UnicodeString ClipboardText;    if (NonEmptyTextFromClipboard(ClipboardText))    {      if (StoredSessions->IsUrl(ClipboardText))      {        NewSession(ClipboardText);      }      else      {        DirView(osCurrent)->Path = ClipboardText;      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileListFromClipboard(){  // TBD}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SelectAll(TOperationSide Side, TSelectMode Mode){  TCustomDirView * ADirView = DirView(Side);  ADirView->SelectAll(Mode);  ADirView->SetFocus();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SelectByMask(TOperationSide Side, bool Select){  TCustomDirView * ADirView = DirView(Side);  TFileFilter Filter;  DefaultFileFilter(Filter);  if (DoSelectMaskDialog(ADirView, Select, Filter))  {    Configuration->Usage->Inc(L"MaskSelections");    ADirView->SelectFiles(Filter, Select);    ADirView->SetFocus();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RestoreSelectedNames(TOperationSide Side){  TCustomDirView * ADirView = DirView(Side);  ADirView->RestoreSelectedNames();  ADirView->SetFocus();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SelectSameExt(bool Select){  TCustomDirView * CurrentDirView = DirView(osCurrent);  if (DebugAlwaysTrue(CurrentDirView->ItemFocused != NULL))  {    UnicodeString FileName = CurrentDirView->ItemFileName(CurrentDirView->ItemFocused);    UnicodeString Ext;    if (!IsSideLocalBrowser(osCurrent))    {      Ext = UnixExtractFileExt(FileName);    }    else    {      Ext = ExtractFileExt(FileName);    }    if (Ext.IsEmpty())    {      Ext = L".";    }    TFileFilter Filter;    Filter.Masks = FORMAT(L"*%s", (Ext));    Filter.Directories = false;    CurrentDirView->SelectFiles(Filter, Select);  }}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::FileStatusBarText(  const TStatusFileInfo & FileInfo, TOperationSide Side){  UnicodeString Result;  if (FIncrementalSearchState.Searching && (Side == GetSide(osCurrent)))  {    Result = FormatIncrementalSearchStatus(FIncrementalSearchState);  }  else if (!IsSideLocalBrowser(Side) && ((Terminal == NULL) || Terminal->Disconnected))  {    // noop  }  else  {    Result =      FMTLOAD(FILE_INFO_FORMAT,        (FormatBytes(FileInfo.SelectedSize),         FormatBytes(FileInfo.FilesSize),         FormatNumber(FileInfo.SelectedCount),         FormatNumber(FileInfo.FilesCount)));  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileStatusBarPanelClick(  TTBXStatusPanel * Panel, TOperationSide Side){  if (Panel->Index == 1)  {    ToggleShowHiddenFiles();  }  else if (Panel->Index == 2)  {    Filter(Side);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateFileStatusBar(  TTBXStatusBar * StatusBar, const TStatusFileInfo & FileInfo, TOperationSide Side){  DebugAssert(!StatusBar->SimplePanel);  StatusBar->Panels->Items[0]->Caption = FileStatusBarText(FileInfo, Side);  UpdateFileStatusExtendedPanels(StatusBar, FileInfo);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateFileStatusExtendedPanels(  TTBXStatusBar * StatusBar, const TStatusFileInfo & FileInfo){  DebugAssert(StatusBar->Panels->Count >= 3);  TTBXStatusPanel * HiddenFilesPanel = StatusBar->Panels->Items[1];  if (FileInfo.HiddenCount > 0)  {    HiddenFilesPanel->Caption = FMTLOAD(FILE_INFO_HIDDEN2, (FormatNumber(FileInfo.HiddenCount)));    HiddenFilesPanel->ViewPriority = 90; // <100 allows hiding panel when it does not fit  }  else  {    HiddenFilesPanel->ViewPriority = 0;    // not really necessary, just to cleanup no-longer-valid data    HiddenFilesPanel->Caption = L"";  }  TTBXStatusPanel * FilteredFilesPanel = StatusBar->Panels->Items[2];  if (FileInfo.FilteredCount > 0)  {    FilteredFilesPanel->Caption = FMTLOAD(FILE_INFO_FILTERED2, (FormatNumber(FileInfo.FilteredCount)));    FilteredFilesPanel->ViewPriority = 90; // <100 allows hiding panel when it does not fit  }  else  {    FilteredFilesPanel->ViewPriority = 0;    // not really necessary, just to cleanup no-longer-valid data    FilteredFilesPanel->Caption = L"";  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteStatusBarClick(  TObject * /*Sender*/){  if (DirView(osOther)->Enabled)  {    DirView(osOther)->SetFocus();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ToggleQueueVisibility(){  TQueueViewConfiguration Config = WinConfiguration->QueueView;  switch (Config.Show)  {    case qvShow:      if ((FQueueStatus != NULL) && (FQueueStatus->Count > 0))      {        Config.Show = qvHide;      }      else      {        Config.Show = Config.LastHideShow;      }      break;    case qvHideWhenEmpty:      if (ComponentVisible[fcQueueView])      {        Config.Show = qvHide;      }      else      {        Config.LastHideShow = Config.Show;        Config.Show = qvShow;      }      break;    case qvHide:      Config.LastHideShow = Config.Show;      Config.Show = qvShow;      break;  }  WinConfiguration->QueueView = Config;}//---------------------------------------------------------------------------UnicodeString __fastcall TCustomScpExplorerForm::PathForCaption(){  UnicodeString Result;  if (Terminal != NULL)  {    switch (WinConfiguration->PathInCaption)    {      case picShort:        Result = ExtractShortName(Terminal->CurrentDirectory, true);        break;      case picFull:        Result = Terminal->CurrentDirectory;        break;    }  }  return Result;}//---------------------------------------------------------------------------TColor __fastcall TCustomScpExplorerForm::PanelColor(){  TColor Result = GetWindowColor(FSessionColor);  return Result;}//---------------------------------------------------------------------------TColor __fastcall TCustomScpExplorerForm::DisabledPanelColor(){  TColor Result = (WinConfiguration->UseDarkTheme() ? static_cast<TColor>(RGB(0x40, 0x40, 0x40)) : clBtnFace);  return Result;}//---------------------------------------------------------------------------void TCustomScpExplorerForm::UpdatePanelControls(TCustomDirView * ADirView, TCustomDriveView * ADriveView){  bool UseDarkTheme = WinConfiguration->UseDarkTheme();  ADirView->DarkMode = UseDarkTheme;  ADriveView->DarkMode = UseDarkTheme;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateControls(){  if (!FSessionChanging)  {    TTerminalManager::Instance()->UpdateAppTitle();  }  // WORKAROUND: Disabling list view when it is not showing yet does not set its  // background to gray on Windows 7 (works on Windows 10).  // See also EnableControl  if (Showing)  {    if (ManagedSession != NULL)    {      // Update path when it changes      if ((SessionsPageControl->ActivePage != NULL) &&          (GetSessionTabSession(SessionsPageControl->ActivePage) == ManagedSession))      {        UpdateSessionTab(SessionsPageControl->ActivePage);      }    }    NonVisualDataModule->ReconnectSessionAction->Update();    ReconnectToolbar->Visible = NonVisualDataModule->ReconnectSessionAction->Visible;    // ReconnectSessionAction is hidden when disabled, so enabling it actualy resizes the toolbar    CenterReconnectToolbar();    bool HasTerminal = HasActiveTerminal();    RemoteDirView->Enabled = HasTerminal;    RemoteDirView->Color = HasTerminal ? PanelColor() : DisabledPanelColor();    RemoteDirView->Font->Color = GetWindowTextColor(RemoteDirView->Color);    RemoteDriveView->Enabled = RemoteDirView->Enabled;    RemoteDriveView->Color = RemoteDirView->Color;    RemoteDriveView->Font->Color = RemoteDirView->Font->Color;    QueueView3->Enabled = HasTerminal && Terminal->IsCapable[fcBackgroundTransfers];    QueueView3->Color = QueueView3->Enabled ? GetWindowColor() : DisabledPanelColor();    QueueView3->Font->Color =  GetWindowTextColor(QueueView3->Color);    QueueFileList->Enabled = QueueView3->Enabled;    QueueFileList->Color = QueueView3->Color;    QueueFileList->Font->Color = QueueView3->Font->Color;    QueueLabelUpdateStatus();    UpdatePanelControls(RemoteDirView, RemoteDriveView);    bool UseDarkTheme = WinConfiguration->UseDarkTheme();    if (FImmersiveDarkMode != UseDarkTheme)    {      UpdateDarkMode();    }    SessionsPageControl->TabTheme = UseDarkTheme ? CurrentTheme : NULL;    UnicodeString CurrentHiContrastThemeName = (FHiContrastTheme != NULL) ? FHiContrastTheme->Name : EmptyStr;    bool HiContrast = WinConfiguration->HiContrast;    UnicodeString NewHiContrastThemeName = HiContrast ? GetThemeName(!UseDarkTheme) : EmptyStr;    if (CurrentHiContrastThemeName != NewHiContrastThemeName)    {      ReleaseHiContrastTheme();      if (!NewHiContrastThemeName.IsEmpty())      {        FHiContrastTheme = GetTBXTheme(NewHiContrastThemeName);      }    }    SessionsPageControl->ActiveTabTheme = HiContrast ? DebugNotNull(FHiContrastTheme) : NULL;    reinterpret_cast<TTBCustomItem *>(GetComponent(fcRemotePathComboBox))->Enabled = HasTerminal || IsLocalBrowserMode();    MessageDock->Visible = (MessageDock->ToolbarCount > 0);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoDirViewLoaded(TCustomDirView * /*Sender*/){  UpdateControls();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewLoaded(  TObject * Sender){  TCustomDirView * DirView = dynamic_cast<TCustomDirView *>(Sender);  DebugAssert(DirView != NULL);  DoDirViewLoaded(DirView);  TransferPresetAutoSelect();  TUnixDirView * UnixDirView = dynamic_cast<TUnixDirView *>(DirView);  if (UnixDirView != NULL)  {    TManagedTerminal * ATerminal = DebugNotNull(dynamic_cast<TManagedTerminal *>(UnixDirView->Terminal));    TTerminalManager::Instance()->TerminalLoadedDirectory(ATerminal);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::StartUpdates(){  TUpdatesConfiguration Updates = WinConfiguration->Updates;  // first run after installation  if (double(Updates.LastCheck) == 0)  {    AppLog(L"First run, scheduling updates check for the next run");    // make sure next time there will be an update (if enabled)    Updates.LastCheck = TDateTime(1);    WinConfiguration->Updates = Updates;  }  else  {    TDateTime Period;    if (IsUWP() && !IsOfficialPackage())    {      Period = DefaultUpdatesPeriod;      AppLog(L"Thirdparty UWP package, using default updates check period");    }    else    {      Period = Updates.Period;    }    AppLogFmt(L"Updates check period: %.2f", (double(Period)));    if (double(Period) > 0)    {      TDateTime Interval = Now() - Updates.LastCheck;      AppLogFmt(L"Interval since the last updates check: %.2f", (double(Interval)));      if (Interval >= Period)      {        StartUpdateThread(UpdatesChecked);      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdatesChecked(){  AppLog(L"Updates check done");  UnicodeString Message;  bool New;  TQueryType Type;  GetUpdatesMessage(Message, New, Type, false);  if (!Message.IsEmpty())  {    AppLogFmt(L"Updates check message: %s", (Message));    if (New)    {      AppLog(L"New version detected");      Message = FMTLOAD(NEW_VERSION_CLICK, (Message));    }    if (!New && (Type != qtWarning))    {      AppLog(L"Posting non-critical updates note");      PostNote(UnformatMessage(Message), 0, UpdatesNoteClicked, NULL);    }    else    {      AppLog(L"Posting new version or critical message notification");      Notify(NULL, Message, Type, true, UpdatesNoteClicked);    }    if (New)    {      Configuration->Usage->Inc(L"UpdateNotifications");    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdatesNoteClicked(TObject * /*Sender*/){  RestoreApp();  bool CanDisplay = !NonVisualDataModule->Busy;  if (!CanDisplay && (Screen->ActiveForm != NULL))  {    CanDisplay = (Screen->ActiveForm->Perform(WM_CAN_DISPLAY_UPDATES, 0, 0) != 0);  }  if (CanDisplay)  {    Configuration->Usage->Inc(L"UpdateNotificationsClicked");    // Probably not needed as CheckForUpdates is blocking since we started using neon for HTTP implementation.    NonVisualDataModule->StartBusy();    try    {      CheckForUpdates(true);    }    __finally    {      NonVisualDataModule->EndBusy();    }  }  else  {    Configuration->Usage->Inc(L"UpdateNotificationsBusy");  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::GetTransferPresetAutoSelectData(  TCopyParamRuleData & Data){  DebugAssert(Terminal != NULL);  Data.HostName = Terminal->SessionData->HostNameExpanded;  Data.UserName = Terminal->SessionData->UserNameExpanded;  Data.RemoteDirectory = RemoteDirView->PathName;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TransferPresetAutoSelect(){  // Terminal can be null when we are changing local directory implicitly,  // because it has been deleted, while no session is connected  // (Login dialog is open)  if (FAllowTransferPresetAutoSelect && (Terminal != NULL))  {    DebugAssert(!IsLocalBrowserMode());    TCopyParamRuleData Data;    GetTransferPresetAutoSelectData(Data);    int CopyParamIndex = GUIConfiguration->CopyParamList->Find(Data);    UnicodeString CopyParamCurrent = GUIConfiguration->CopyParamCurrent;    if (CopyParamIndex < 0)    {      // there is no preset that matches autoselection      // set preset that we consider "default"      FCopyParamAutoSelected = L""; // forget last autoselected preset      GUIConfiguration->CopyParamCurrent = FCopyParamDefault;    }    else    {      // there is preset matching autoselection      UnicodeString CopyParamName = GUIConfiguration->CopyParamList->Names[CopyParamIndex];      if (CopyParamName == FCopyParamAutoSelected)      {        // autoselected the same preset as the last time        // make no change (i.e. preserve custom user preset, if any)      }      else      {        // autoselected the different preset then the last time (or there        // was default preset set)        FCopyParamAutoSelected = CopyParamName; // remember autoselection        GUIConfiguration->CopyParamCurrent = CopyParamName;      }    }    if (GUIConfiguration->CopyParamCurrent != CopyParamCurrent)    {      if (CopyParamIndex >= 0)      {        Configuration->Usage->Inc(L"CopyParamAutoSelects");      }      TTransferPresetNoteData * Data = new TTransferPresetNoteData;      try      {        int Fmt =          (CopyParamIndex < 0) ?            (GUIConfiguration->CopyParamIndex < 0 ? COPY_PARAM_DEFAULT_NORM : COPY_PARAM_DEFAULT_CUSTOM) :            COPY_PARAM_AUTOSELECTED;        UnicodeString Message = FMTLOAD(Fmt, (StripHotkey(GUIConfiguration->CopyParamCurrent)));        Data->Message = MainInstructions(Message);        int CopyParamAttrs = Terminal->UsableCopyParamAttrs(0).General;        UnicodeString Info = GUIConfiguration->CurrentCopyParam.GetInfoStr(L"\n",          CopyParamAttrs);        if (CopyParamIndex >= 0)        {          DebugAssert(GUIConfiguration->CopyParamList->Rules[CopyParamIndex] != NULL);          Info = FORMAT(L"%s\n \n%s", (Info,            FMTLOAD(COPY_PARAM_RULE,              (GUIConfiguration->CopyParamList->Rules[CopyParamIndex]->GetInfoStr(L"\n")))));        }        Data->Message += L"\n\n" + Info;        if (WinConfiguration->CopyParamAutoSelectNotice)        {          TransferPresetNoteMessage(Data, true);        }        else        {          PostNote(Message, 0, TransferPresetNoteClicked, Data);          Data = NULL; // ownership passed        }      }      __finally      {        delete Data;      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TransferPresetNoteMessage(  TTransferPresetNoteData * NoteData, bool AllowNeverAskAgain){  DebugAssert(NoteData != NULL);  DebugAssert(!IsLocalBrowserMode());  TMessageParams Params(AllowNeverAskAgain ? mpNeverAskAgainCheck : 0);  TQueryButtonAlias Aliases[1];  Aliases[0].Button = qaIgnore; // "ignore" is after "ok"  Aliases[0].Alias = LoadStr(CONFIGURE_BUTTON);  Params.Aliases = Aliases;  Params.AliasesCount = LENOF(Aliases);  unsigned int Result =    MoreMessageDialog(NoteData->Message, NULL, qtInformation,      qaOK | qaIgnore, HELP_COPY_PARAM_AUTOSELECTED, &Params);  switch (Result)  {    case qaNeverAskAgain:      DebugAssert(AllowNeverAskAgain);      WinConfiguration->CopyParamAutoSelectNotice = false;      break;    case qaIgnore:      PreferencesDialog(pmPresets);      break;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::TransferPresetNoteClicked(TObject * Sender){  // as of now useless, as this is used for notes only, never for balloons, ...  RestoreApp();  // .. and we should never be busy here  if (DebugAlwaysTrue(!NonVisualDataModule->Busy))  {    TransferPresetNoteMessage(DebugNotNull(dynamic_cast<TTransferPresetNoteData *>(Sender)), false);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::PreferencesDialog(  TPreferencesMode APreferencesMode){  std::unique_ptr<TPreferencesDialogData> PreferencesData;  TCopyParamRuleData Data;  if (Terminal != NULL)  {    PreferencesData.reset(new TPreferencesDialogData());    GetTransferPresetAutoSelectData(Data);    PreferencesData->CopyParamRuleData = &Data;  }  DoPreferencesDialog(APreferencesMode, PreferencesData.get());}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AdHocCustomCommandValidate(  const TCustomCommandType & Command){  if (CustomCommandState(Command, FEditingFocusedAdHocCommand, ccltAll) <= 0)  {    throw Exception(FMTLOAD(CUSTOM_COMMAND_IMPOSSIBLE2, (Command.Command)));  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AdHocCustomCommand(bool OnFocused){  bool RemoteAllowed = CustomCommandRemoteAllowed();  TCustomCommandType Command;  // make sure we use local custom command when remote are not supported  if (RemoteAllowed || FLAGSET(FLastCustomCommand.Params, ccLocal))  {    Command = FLastCustomCommand;  }  else  {    Command.Params = Command.Params | ccLocal;  }  Command.Name = LoadStr(CUSTOM_COMMAND_AD_HOC_NAME);  FEditingFocusedAdHocCommand = OnFocused;  bool LocalSide = IsSideLocalBrowser(FCurrentSide);  int Options =    FLAGMASK((!RemoteAllowed || LocalSide), ccoDisableRemote) |    FLAGMASK(LocalSide, ccoDisableRemoteFiles);  if (DoCustomCommandDialog(Command, WinConfiguration->CustomCommandList,       ccmAdHoc, Options, AdHocCustomCommandValidate, NULL))  {    FLastCustomCommand = Command;    UpdateCustomCommandsToolbar();    ExecuteFileOperation(foCustomCommand, osRemote, OnFocused, false, &Command);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LastCustomCommand(bool OnFocused){  DebugAssert(!FLastCustomCommand.Command.IsEmpty());  int State = CustomCommandState(FLastCustomCommand, OnFocused, ccltAll);  DebugAssert(State > 0);  if (State <= 0)  {    throw Exception(FMTLOAD(CUSTOM_COMMAND_IMPOSSIBLE2, (FLastCustomCommand.Command)));  }  ExecuteFileOperation(foCustomCommand, osRemote, OnFocused, false, &FLastCustomCommand);}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::GetLastCustomCommand(bool OnFocused,  TCustomCommandType & Command, int & State){  bool Result = !FLastCustomCommand.Command.IsEmpty();  if (Result)  {    Command = FLastCustomCommand;    State = CustomCommandState(FLastCustomCommand, OnFocused, ccltAll);  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::BeforeAction(){  ResetIncrementalSearch();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::PostComponentHide(Byte Component){  DebugAssert(ComponentVisible[Component]);  PostMessage(Handle, WM_COMPONENT_HIDE, Component, 0);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueSplitterDblClick(TObject * /*Sender*/){  // when queue panel is resized here directly, the status bar is stretched  // over whole space the panel occupied  PostComponentHide(fcQueueView);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueFileListSplitterDblClick(TObject *){  ComponentVisible[fcQueueFileList] = false;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ThemeChanged(){  // We hoped this will refresh scrollbar colors, but it does not have any effect here.  RefreshColorMode();  ResetSysDarkTheme();  ConfigurationChanged();  ConfigureInterface();  // Should be called for all controls  RemoteDirView->Perform(WM_THEMECHANGED, 0, 0);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::WMSettingChange(TMessage & Message){  // Do not handle, when shutting down anyway (maybe also when not setup completely yet?)  if (!FInvalid &&      (Message.LParam != 0) &&      (wcscmp(reinterpret_cast<LPCWCH>(Message.LParam), L"ImmersiveColorSet") == 0))  {    ThemeChanged();  }  TForm::Dispatch(&Message);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::Dispatch(void * Message){  TMessage * M = static_cast<TMessage*>(Message);  switch (M->Msg)  {    case CM_DIALOGCHAR:      CMDialogChar(*M);      break;    case WM_APPCOMMAND:      WMAppCommand(*M);      break;    case WM_SYSCOMMAND:      WMSysCommand(*M);      break;    case WM_QUERYENDSESSION:      WMQueryEndSession(*M);      break;    case WM_ENDSESSION:      WMEndSession(*reinterpret_cast<TWMEndSession *>(M));      break;#ifdef _DEBUG    case WM_WINDOWPOSCHANGED:      WMWindowPosChanged(*reinterpret_cast<TWMWindowPosMsg *>(M));      break;    case CM_CUSTOMSTYLECHANGED:      TForm::Dispatch(Message);      break;#endif    case WM_COMPONENT_HIDE:      {        Byte Component = static_cast<Byte>(M->WParam);        // sanity check        if (ComponentVisible[Component])        {          // special treatment          if (Component == fcQueueView)          {            ToggleQueueVisibility();            DebugAssert(!ComponentVisible[fcQueueView]);          }          else          {            ComponentVisible[Component] = false;          }        }      }      break;    case WM_COPYDATA:      WMCopyData(*M);      break;    case WM_MANAGES_CAPTION:      // caption managed in TTerminalManager::UpdateAppTitle()      M->Result = 1;      break;    case WM_WANTS_MOUSEWHEEL:      M->Result = 1;      break;    case CM_SHOWINGCHANGED:      CMShowingChanged(*M);      break;    case WM_CLOSE:      WMClose(*M);      break;    case WM_DPICHANGED:      WMDpiChanged(*M);      break;    case WM_SETTINGCHANGE:      WMSettingChange(*M);      break;    case CM_DIALOGKEY:      CMDialogKey(*reinterpret_cast<TWMKeyDown *>(M));      break;    case WM_PASTE_FILES:      PasteFiles();      break;    case WM_IS_HIDDEN:      // To treat master password prompt as a main window while showing it when workspace is loading while      // the exporer is showing up (Visible is true already)      M->Result = !FShowing;      break;    case WM_SHOWWINDOW:      if (M->WParam)      {        AddStartupSequence(L"J");      }      TForm::Dispatch(Message);      break;    case WM_QUEUE_CALLBACK:      WMQueueCallback(*M);      break;    default:      TForm::Dispatch(Message);      break;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateImages(){  // noop}//---------------------------------------------------------------------------void TCustomScpExplorerForm::RegenerateSessionColorsImageList(){  FSessionColors->Clear();  AddFixedSessionImages();  ::RegenerateSessionColorsImageList(FSessionColors, FSessionColorMaskImageIndex);  UpdateImages();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::WMDpiChanged(TMessage & Message){  TForm::Dispatch(&Message);  Configuration->Usage->Inc(L"PixelsPerInchChanged");  UpdatePixelsPerInchMainWindowCounter();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::WMClose(TMessage & Message){  AppLog(L"Main window WM_CLOSE");  // Cannot close window while we are busy.  // We cannot test this in FormCloseQuery as that is called also from  // Close(), which is called by CloseApplicationAction. So we can be busy  // there already even, when it is legitimate to close the application.  // Possibly a better place to handle this would be WMSysCommand.  if (NonVisualDataModule->Busy)  {    Message.Result = 1;  }  else  {    TForm::Dispatch(&Message);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CMShowingChanged(TMessage & Message){  if (!FShowingChanged)  {    AddStartupSequence(L"D");    FShowingChanged = true;  }  // Ignoring implicit local-local browser of Commander, opened from DoShow  bool NoSession = (ManagedSession == NULL);  // This calls TCustomScpExplorerForm::DoShow  TForm::Dispatch(&Message);  // Now the window is visible (TForm::Dispatch is what usually takes long, like when loading a "local" network directory)  if (Showing && !FStarted)  {    FStarted = true;    InterfaceStarted();  }  if (Showing && NoSession)  {    // When we are starting minimized (i.e. from an installer),    // postpone showing Login dialog until we get restored.    // Otherwise the Login dialog (and Authentication window) show restored    // over invisible (minimized) main window.    if (WindowState == wsMinimized)    {      FNeedSession = true;    }    else    {      // This happens before application ever goes idle, so the toolbars would      // stay enabled (initial state) until the Login dialog is dismissed.      UpdateActions();      NonVisualDataModule->StartBusy();      try      {        // Need to process WM_ACTIVATEAPP before showing the Login dialog,        // otherwise the dialog does not receive focus.        // With Commander interface the ProcessMessages is called already        // by TDriveView, but with Explorer interface, we need to call it explicily        Application->ProcessMessages();        // do not reload sessions, they have been loaded just now (optimization)        NeedSession(true);      }      __finally      {        NonVisualDataModule->EndBusy();      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CenterReconnectToolbar(){  ReconnectToolbar->Left = (ReconnectToolbar->Parent->ClientWidth - ReconnectToolbar->Width) / 2;  ReconnectToolbar->Top = (ReconnectToolbar->Parent->ClientHeight - ReconnectToolbar->Height) / 2;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FormConstrainedResize(  TObject * /*Sender*/, int & MinWidth, int & MinHeight, int & MaxWidth,  int & MaxHeight){  // workaround for bug in TWinControl.CalcConstraints  // Check for empty rect (restore from iconic state) is done there only after  // call to AdjustClientRect, which enlarges the rect (for forms).  TRect R = GetClientRect();  // when restoring from iconic state, place no restrictions  if (IsRectEmpty(R))  {    MinWidth = 0;    MinHeight = 0;    MaxWidth = 32000;    MaxHeight = 32000;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::GetSpaceAvailable(const UnicodeString Path,  TSpaceAvailable & ASpaceAvailable, bool & Close){  // terminal can be already closed (e.g. dropped connection)  if ((Terminal != NULL) && Terminal->IsCapable[fcCheckingSpaceAvailable])  {    Configuration->Usage->Inc(L"SpaceAvailableChecks");    try    {      Terminal->SpaceAvailable(Path, ASpaceAvailable);    }    catch(...)    {      if (!Terminal->Active)      {        Close = true;      }      throw;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileSystemInfo(){  const TSessionInfo & SessionInfo = Terminal->GetSessionInfo();  const TFileSystemInfo & FileSystemInfo = Terminal->GetFileSystemInfo(true);  TGetSpaceAvailable OnGetSpaceAvailable = NULL;  if (Terminal->IsCapable[fcCheckingSpaceAvailable])  {    OnGetSpaceAvailable = GetSpaceAvailable;  }  DoFileSystemInfoDialog(SessionInfo, FileSystemInfo, Terminal->CurrentDirectory,    OnGetSpaceAvailable);}//---------------------------------------------------------------------------TSessionData * __fastcall TCustomScpExplorerForm::SessionDataForCode(){  std::unique_ptr<TSessionData> Data(CloneCurrentSessionData());  Terminal->FillSessionDataForCode(Data.get());  return Data.release();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::GenerateUrl(TStrings * Paths){  std::unique_ptr<TSessionData> Data(SessionDataForCode());  DoGenerateUrlDialog(Data.get(), Paths);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionGenerateUrl(){  GenerateUrl(NULL);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FileGenerateUrl(){  std::unique_ptr<TStrings> Paths(new TStringList());  DirView(osCurrent)->CreateFileList(false, true, Paths.get());  GenerateUrl(Paths.get());}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateSessionColor(TColor value){  FSessionColor = value;  TColor C = (value != 0 ? value : Vcl::Graphics::clNone);  TTBXColorItem * ColorItem = dynamic_cast<TTBXColorItem *>(    static_cast<TObject *>(GetComponent(fcColorMenu)));  DebugAssert(ColorItem != NULL);  ColorItem->Color = C;  NonVisualDataModule->ColorMenuItem->Color = C;  UpdateControls();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetSessionColor(TColor value){  if (value != FSessionColor)  {    UpdateSessionColor(value);    // Is null when called from LastTerminalClosed    if (Terminal != NULL)    {      SessionsPageControl->ActivePage->ImageIndex = AddSessionColor(value);    }  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CancelNote(bool Force){  bool Result = FNoteTimer->Enabled;  if (Result)  {    // cannot cancel note too early    bool NotEarly =      (Now() - FNoteShown >          EncodeTimeVerbose(0, 0, (unsigned short)(WinConfiguration->NotificationsStickTime), 0));    if (Force || NotEarly)    {      FNoteTimer->Enabled = false;      FNote = L"";      SAFE_DESTROY(FNoteData);      FOnNoteClick = NULL;      FNoteHints = FNotes->Text;      FNoteHints.Delete(FNoteHints.Length() - 1, 2);      UpdateStatusBar();    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::NoteTimer(TObject * /*Sender*/){  DebugAssert(FNoteTimer->Enabled);  CancelNote(true);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateNoteHints(){  FNoteHints = FNotes->Text.TrimRight();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AddNote(UnicodeString Note, bool UpdateNow){  int P = Note.Pos(L"\n");  if (P > 0)  {    Note.SetLength(P - 1);  }  FNotes->Add(FORMAT(L"[%s] %s",    (FormatDateTime(Configuration->TimeFormat, Now()), Note)));  while (FNotes->Count > 10)  {    FNotes->Delete(0);  }  if (UpdateNow)  {    UpdateNoteHints();    UpdateStatusBar();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::PostNote(UnicodeString Note,  unsigned int Seconds, TNotifyEvent OnNoteClick, TObject * NoteData){  int P = Note.Pos(L"\n");  if (P > 0)  {    Note.SetLength(P - 1);  }  UpdateNoteHints();  FNote = Note;  SAFE_DESTROY(FNoteData);  FNoteData = NoteData;  FOnNoteClick = OnNoteClick;  AddNote(Note, false);  UpdateStatusBar();  FNoteShown = Now();  FNoteTimer->Enabled = false;  if (Seconds == 0)  {    Seconds = WinConfiguration->NotificationsTimeout;  }  FNoteTimer->Interval = Seconds * MSecsPerSec;  FNoteTimer->Enabled = true;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ReadDirectoryCancelled(){  PostNote(LoadStr(DIRECTORY_READING_CANCELLED), 0, NULL, NULL);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SynchronizeBrowsingChanged(){  if (NonVisualDataModule->SynchronizeBrowsingAction2->Checked)  {    Configuration->Usage->Inc(L"SynchronizeBrowsingEnabled");  }  PostNote(FORMAT(LoadStrPart(SYNC_DIR_BROWSE_TOGGLE, 1),    (LoadStrPart(SYNC_DIR_BROWSE_TOGGLE,      (NonVisualDataModule->SynchronizeBrowsingAction2->Checked ? 2 : 3)))),    0, NULL, NULL);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ToggleShowHiddenFiles(){  bool NewShowHiddenFiles = !WinConfiguration->ShowHiddenFiles;  UnicodeString Note =    FORMAT(LoadStrPart(SHOW_HIDDEN_FILES_TOGGLE, 1), (LoadStrPart(SHOW_HIDDEN_FILES_TOGGLE, (NewShowHiddenFiles ? 2 : 3))));  PostNote(Note, 0, NULL, NULL);  GetComponent(fcStatusBar)->Repaint(); // toggling ShowHiddenFiles takes time, force repaint beforehand  WinConfiguration->ShowHiddenFiles = NewShowHiddenFiles;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SetFormatSizeBytes(TFormatBytesStyle Style){  WinConfiguration->FormatSizeBytes = Style;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ToggleAutoReadDirectoryAfterOp(){  Configuration->AutoReadDirectoryAfterOp = !Configuration->AutoReadDirectoryAfterOp;  PostNote(FORMAT(LoadStrPart(AUTO_READ_DIRECTORY_TOGGLE, 1),    (LoadStrPart(AUTO_READ_DIRECTORY_TOGGLE,      (Configuration->AutoReadDirectoryAfterOp ? 2 : 3)))), 0, NULL, NULL);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::StatusBarPanelDblClick(  TTBXCustomStatusBar * Sender, TTBXStatusPanel * Panel){  if (Panel->Index == 0)  {    if (FOnNoteClick != NULL)    {      // prevent the user data from being freed by possible call      // to CancelNote or PostNote during call to OnNoteClick      std::unique_ptr<TObject> NoteData(FNoteData);      TNotifyEvent OnNoteClick = FOnNoteClick;      FNoteData = NULL;      // need to cancel the note as we are going to delete its user data      CancelNote(true);      OnNoteClick(NoteData.get());    }  }  if (HasActiveTerminal() &&      (Panel->Index >= Sender->Panels->Count - SessionPanelCount))  {    FileSystemInfo();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LockWindow(bool Force){  // workaround:  // 1) for unknown reason, disabling window, while minimized,  // prevents it from restoring, even if it was enabled again meanwhile  // 2) when disabling the main window, while another has focus  // minimize is no longer possible  // ("keep up to date" dialog - though does not seem to be the case with "find file" -  // so it has probably something to do with the semi-modalness of the "keep up to date" dialog)  // Shouldn't we use IsApplicationMinimized() here?  if ((FLockSuspendLevel == 0) && !IsIconic(Application->Handle) && (Force || (Screen->ActiveForm == this)))  {    Enabled = false;  }  FLockLevel++;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UnlockWindow(){  DebugAssert(FLockLevel > 0);  FLockLevel--;  if (FLockLevel == 0)  {    DebugAssert(FLockSuspendLevel == 0);    Enabled = true;    // VCL_COPY (TCustomForm.SetWindowFocus)    if (Active && (ActiveControl != NULL))    {      ::SetFocus(ActiveControl->Handle);      if (GetFocus() == ActiveControl->Handle)      {        ActiveControl->Perform(CM_UIACTIVATE, 0, 0);      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SuspendWindowLock(){  // We need to make sure that window is enabled when the last modal window closes  // otherwise focus is not restored correctly.  // So we re-enable the window when modal window opens and  // disable it back after is closes  if (FLockLevel > 0)  {    // while we have nesting counter, we know that we never be called    // recursivelly as Application->OnModalBegin is called only    // for the top-level modal window    if (DebugAlwaysTrue(FLockSuspendLevel == 0))    {      // won't be disabled when conditions in LockWindow() were not satisfied      FDisabledOnLockSuspend = !Enabled;      // When minimized to tray (or actually when set to SW_HIDE),      // setting Enabled makes the window focusable even when there's      // modal window over it      if (!FTrayIcon->Visible)      {        Enabled = true;      }    }    FLockSuspendLevel++;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ResumeWindowLock(){  if (FLockSuspendLevel > 0)  {    DebugAssert(FLockLevel > 0);    FLockSuspendLevel--;    // see comment in SuspendWindowLock    if (DebugAlwaysTrue(FLockSuspendLevel == 0))    {      // Note that window can be enabled here, when we were minized to tray when      // was SuspendWindowLock() called.      // We should possibly do the same check as in LockWindow(),      // if it is ever possible that the consitions change between      // SuspendWindowLock() and ResumeWindowLock()      Enabled = !FDisabledOnLockSuspend;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateRemotePathComboBox(bool TextOnly){  TTBXComboBoxItem * RemotePathComboBox =    reinterpret_cast<TTBXComboBoxItem *>(GetComponent(fcRemotePathComboBox));  if (!TextOnly)  {    TStrings * Items = RemotePathComboBox->Strings;    Items->BeginUpdate();    try    {      Items->Clear();      if ((Terminal != NULL) && !RemoteDirView->Path.IsEmpty())      {        UnicodeString APath = UnixExcludeTrailingBackslash(RemoteDirView->Path);        while (!IsUnixRootPath(APath))        {          int P = APath.LastDelimiter(L'/');          DebugAssert(P >= 0);          Items->Insert(0, APath.SubString(P + 1, APath.Length() - P));          APath.SetLength(P - 1);        }        Items->Insert(0, Customunixdirview_SUnixDefaultRootName);      }    }    __finally    {      Items->EndUpdate();    }  }  RemotePathComboBox->ItemIndex = RemotePathComboBox->Strings->Count - 1;  // Setting ItemIndex to -1 does not reset its text  if (RemotePathComboBox->Strings->Count == 0)  {    RemotePathComboBox->Text = L"";  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoRemotePathComboBoxAdjustImageIndex(  TTBXComboBoxItem * Sender, const UnicodeString DebugUsedArg(AText), int AIndex, int & ImageIndex){  if (AIndex < 0)  {    AIndex = Sender->ItemIndex;  }  ImageIndex = (AIndex < Sender->Strings->Count - 1 ? StdDirIcon : StdDirSelIcon);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemotePathComboBoxAdjustImageIndex(  TTBXComboBoxItem * Sender, const UnicodeString AText, int AIndex,  int & ImageIndex){  DoRemotePathComboBoxAdjustImageIndex(Sender, AText, AIndex, ImageIndex);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemotePathComboBoxDrawItem(  TTBXCustomList * /*Sender*/, TCanvas * /*ACanvas*/, TRect & ARect, int AIndex,  int /*AHoverIndex*/, bool & /*DrawDefault*/){  if (!IsLocalBrowserMode())  {    ARect.Left += (10 * AIndex);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemotePathComboBoxMeasureWidth(  TTBXCustomList * /*Sender*/, TCanvas * /*ACanvas*/, int AIndex, int &AWidth){  AWidth += (10 * AIndex);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoRemotePathComboBoxItemClick(TObject * Sender){  TTBXComboBoxItem * RemotePathComboBox = dynamic_cast<TTBXComboBoxItem*>(Sender);  UnicodeString APath = UnixExcludeTrailingBackslash(RemoteDirView->Path);  int Index = RemotePathComboBox->ItemIndex;  while (Index < RemotePathComboBox->Strings->Count - 1)  {    APath = UnixExtractFileDir(APath);    Index++;  }  // VanDyke style paths  if (APath.IsEmpty())  {    DebugAssert(RemotePathComboBox->ItemIndex == 0);    APath = ROOTDIRECTORY;  }  if (RemoteDirView->Path != APath)  {    RemoteDirView->Path = APath;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemotePathComboBoxItemClick(TObject * Sender){  DoRemotePathComboBoxItemClick(Sender);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoRemotePathComboBoxCancel(TObject * Sender){  DebugAssert(Sender == GetComponent(fcRemotePathComboBox));  DebugUsedParam(Sender);  UpdateRemotePathComboBox(true);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemotePathComboBoxCancel(TObject * Sender){  DoRemotePathComboBoxCancel(Sender);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewEditing(  TObject * Sender, TListItem * Item, bool & /*AllowEdit*/){  ResetIncrementalSearch();  TCustomDirView * DirView = dynamic_cast<TCustomDirView *>(Sender);  DebugAssert(DirView != NULL);  if (!WinConfiguration->RenameWholeName && !DirView->ItemIsDirectory(Item))  {    HWND Edit = ListView_GetEditControl(DirView->Handle);    // OnEditing is called also from TCustomListView::CanEdit    if (Edit != NULL)    {      EditSelectBaseName(Edit);    }  }}//---------------------------------------------------------------------------//---------------------------------------------------------------------------TDragDropFilesEx * __fastcall TCustomScpExplorerForm::CreateDragDropFilesEx(){  TDragDropFilesEx * Result = new TDragDropFilesEx(this);  Result->AutoDetectDnD = false;  Result->NeedValid = TFileExMustDnDSet() << nvFilename;  Result->RenderDataOn = rdoEnterAndDropSync;  Result->TargetEffects = TDropEffectSet() << deCopy << deMove;  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateDarkMode(){  if (IsWin10Build(19041))  {    FImmersiveDarkMode = WinConfiguration->UseDarkTheme();    BOOL DarkMode = FImmersiveDarkMode ? TRUE : FALSE;    const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20;    DwmSetWindowAttribute(Handle, DWMWA_USE_IMMERSIVE_DARK_MODE, &DarkMode, sizeof(DarkMode));  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CreateWnd(){  TForm::CreateWnd();  // win32-darkmode calls AllowDarkModeForWindow(this, true) here, but it does not seem to have any effect  UpdateDarkMode();  if (FSessionsDragDropFilesEx == NULL)  {    FSessionsDragDropFilesEx = CreateDragDropFilesEx();    FSessionsDragDropFilesEx->OnDragOver = SessionsDDDragOver;    FSessionsDragDropFilesEx->OnProcessDropped = SessionsDDProcessDropped;    FSessionsDragDropFilesEx->OnDragEnter = SessionsDDDragEnter;    FSessionsDragDropFilesEx->OnDragLeave = SessionsDDDragLeave;  }  if (FQueueDragDropFilesEx == NULL)  {    FQueueDragDropFilesEx = CreateDragDropFilesEx();    // No need to set OnDragOver as we do not have any restrictions    FQueueDragDropFilesEx->OnProcessDropped = QueueDDProcessDropped;    FQueueDragDropFilesEx->OnDragEnter = QueueDDDragEnter;    FQueueDragDropFilesEx->OnDragLeave = QueueDDDragLeave;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DestroyWnd(){  TForm::DestroyWnd();  FSessionsDragDropFilesEx->DragDropControl = NULL;  FQueueDragDropFilesEx->DragDropControl = NULL;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FormShow(TObject * /*Sender*/){  SideEnter(FCurrentSide);  FEverShown = true;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoFindFiles(  TTerminal * ATerminal, UnicodeString Directory, const TFileMasks & FileMask,  TFileFoundEvent OnFileFound, TFindingFileEvent OnFindingFile){  if (!NonVisualDataModule->Busy)  {    TTerminalManager::Instance()->ActiveSession = DebugNotNull(dynamic_cast<TManagedTerminal *>(ATerminal));    Configuration->Usage->Inc(L"FileFinds");    LockWindow(true);    NonVisualDataModule->StartBusy();    WinConfiguration->LockedInterface = true;    try    {      Terminal->FilesFind(Directory, FileMask, OnFileFound, OnFindingFile);    }    __finally    {      WinConfiguration->LockedInterface = false;      NonVisualDataModule->EndBusy();      UnlockWindow();    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoFocusRemotePath(TTerminal * ATerminal, const UnicodeString & Path){  if (!NonVisualDataModule->Busy)  {    TTerminalManager::Instance()->ActiveSession = DebugNotNull(dynamic_cast<TManagedTerminal *>(ATerminal));    SetFocus();    RemoteDirView->Path = UnixExtractFilePath(Path);    UnicodeString FileName = UnixExtractFileName(Path);    TListItem * Item = RemoteDirView->FindFileItem(FileName);    // If not found, it can because we have loaded directory from cache and the file is new, try again after reload.    // (tbd: we should not even try this, if we have not loaded the directory from the cache)    if (Item == NULL)    {      ReloadDirectory(osRemote);      Item = RemoteDirView->FindFileItem(FileName);    }    if (Item != NULL)    {      RemoteDirView->ItemFocused = Item;      RemoteDirView->ItemFocused->MakeVisible(false);      RemoteDirView->SetFocus();    }  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanOperateOnFoundFiles(TTerminal * ATerminal){  bool Result = !NonVisualDataModule->Busy;  if (Result)  {    TTerminalManager::Instance()->ActiveSession = DebugNotNull(dynamic_cast<TManagedTerminal *>(ATerminal));  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoOperationOnFoundFiles(  TFileOperation Operation, TTerminal * ATerminal, TStrings * FileList, TFileOperationFinishedEvent OnFileOperationFinished){  if (CanOperateOnFoundFiles(ATerminal))  {    TValueRestorer<TFileOperationFinishedEvent> OnFileOperationFinishedRestorer(FOnFileOperationFinished, OnFileOperationFinished);    ExecuteFileOperation(Operation, osRemote, FileList, false, NULL);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoDeleteFoundFiles(  TTerminal * ATerminal, TStrings * FileList, TFileOperationFinishedEvent OnFileOperationFinished){  DoOperationOnFoundFiles(foDelete, ATerminal, FileList, OnFileOperationFinished);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoDownloadFoundFiles(  TTerminal * ATerminal, TStrings * FileList, TFileOperationFinishedEvent OnFileOperationFinished){  DoOperationOnFoundFiles(foCopy, ATerminal, FileList, OnFileOperationFinished);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoEditFoundFiles(  TTerminal * ATerminal, TStrings * FileList, TFileOperationFinishedEvent OnFileOperationFinished){  if (CanOperateOnFoundFiles(ATerminal))  {    for (int Index = 0; Index < FileList->Count; Index++)    {      UnicodeString FileName = FileList->Strings[Index];      TRemoteFile * File = static_cast<TRemoteFile *>(FileList->Objects[Index]);      ExecuteRemoteFile(FileName, File, efDefaultEditor);      OnFileOperationFinished(osRemote, FileName, true);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteFindFiles(){  FFileFindTerminal = Terminal;  ShowFileFindDialog(    Terminal, RemoteDirView->Path, DoFindFiles, DoFocusRemotePath, DoDeleteFoundFiles,    DoDownloadFoundFiles, DoEditFoundFiles);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateTaskbarList(ITaskbarList3 * TaskbarList){  FTaskbarList = TaskbarList;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsPageControlMouseDown(  TObject * /*Sender*/, TMouseButton Button, TShiftState /*Shift*/, int X, int Y){  int Index = SessionsPageControl->IndexOfTabAt(X, Y);  if (Index >= 0)  {    if (Button == mbLeft)    {      // WORKAROUND: "Mouse down" is raised only after tab is switched.      // If switching tab (switching session) takes long enough for user      // to actually release the button, "mouse down" is still raised,      // but we do not get "mouse up" event, so dragging is not cancelled,      // prevent that by not beginning dragging in the first place.      int Key = ((GetSystemMetrics(SM_SWAPBUTTON) == 0) ? VK_LBUTTON : VK_RBUTTON);      if (IsKeyPressed(Key))      {        // when user clicks the "+", we get mouse down only after the session        // is closed, when new session tab is already on X:Y, so dragging        // starts, prevent that        if (MilliSecondsBetween(Now(), FSessionsPageControlNewTabTime) > 500)        {          TTerminal * Terminal = GetSessionTabSession(SessionsPageControl->Pages[Index]);          if (Terminal != NULL)          {            SessionsPageControl->BeginDrag(false);          }        }      }    }    else if (Button == mbMiddle)    {      // ignore middle-click for "New session tab" and the last local-local tab      TManagedTerminal * Session = GetSessionTabSession(SessionsPageControl->Pages[Index]);      if ((Session != NULL) && CanCloseSession(Session))      {        CloseSessionTab(Index);      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsPageControlDragDrop(  TObject * /*Sender*/, TObject * /*Source*/, int X, int Y){  int Index = SessionsPageControl->IndexOfTabAt(X, Y);  // do not allow dropping on the "+" tab  TTerminal * TargetTerminal = GetSessionTabSession(SessionsPageControl->Pages[Index]);  if ((TargetTerminal != NULL) &&      (SessionsPageControl->ActivePage->PageIndex != Index))  {    Configuration->Usage->Inc(L"SessionTabMoves");    // this is almost redundant as we would recreate tabs in SessionListChanged,    // but we want to actually prevent that to avoid flicker    SessionsPageControl->ActivePage->PageIndex = Index;    TTerminal * Terminal = GetSessionTabSession(SessionsPageControl->ActivePage);    TTerminalManager::Instance()->Move(Terminal, TargetTerminal);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsPageControlDragOver(  TObject * Sender, TObject * Source, int X, int Y,  TDragState /*State*/, bool & Accept){  Accept = (Sender == Source);  if (Accept)  {    int Index = SessionsPageControl->IndexOfTabAt(X, Y);    TTerminal * Terminal = GetSessionTabSession(SessionsPageControl->Pages[Index]);    // do not allow dragging to the "+" tab    Accept = (Terminal != NULL);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsDDDragOver(  int DebugUsedArg(KeyState), const TPoint & Point, int & Effect, int DebugUsedArg(PreferredEffect)){  int Index = SessionsPageControl->IndexOfTabAt(Point.X, Point.Y);  if (Index < 0)  {    Effect = DROPEFFECT_NONE;  }  else  {    TManagedTerminal * TargetSession = GetSessionTabSession(SessionsPageControl->Pages[Index]);    // do not allow dropping on the "+" tab or on disconnected or local-local tabs    if (!IsActiveTerminal(TargetSession) || DebugAlwaysFalse(TargetSession->LocalBrowser))    {      Effect = DROPEFFECT_NONE;    }    else if ((TargetSession != Terminal) && (Effect == DROPEFFECT_MOVE))    {      Effect = DROPEFFECT_COPY;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsDDProcessDropped(  TObject * /*Sender*/, int /*KeyState*/, const TPoint & Point, int Effect){  int Index = SessionsPageControl->IndexOfTabAt(Point.X, Point.Y);  // do not allow dropping on local-local, disconnected and the "+" tab  // (though we do not seem to get here in that case anyway, contrary to RemoteFileControlDDTargetDrop)  TManagedTerminal * TargetTerminal = GetSessionTabSession(SessionsPageControl->Pages[Index]);  if (DebugAlwaysTrue(IsActiveTerminal(TargetTerminal) && !TargetTerminal->LocalBrowser))  {    DebugAssert(!IsFileControl(DropSourceControl, osRemote));    if (!IsFileControl(DropSourceControl, osRemote))    {      TTerminalManager::Instance()->ActiveSession = TargetTerminal;      RemoteFileControlDragDropFileOperation(SessionsPageControl, Effect,        // Why don't we use Terminal->CurrentDirectory directly?        TTerminalManager::Instance()->ActiveTerminal->CurrentDirectory,        // do not force queue, drag drop        false, true);    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueDDProcessDropped(  TObject * /*Sender*/, int /*KeyState*/, const TPoint & /*Point*/, int Effect){  // Downloads are handled in RemoteFileControlDDEnd  if (!IsFileControl(DropSourceControl, osRemote))  {    RemoteFileControlDragDropFileOperation(QueueView3, Effect,      Terminal->CurrentDirectory,      // force queue, drag drop      true, true);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FormClose(TObject * /*Sender*/, TCloseAction & /*Action*/){  FShowing = false;  // Do not save empty workspace  if (WinConfiguration->AutoSaveWorkspace && (ManagedSession != NULL))  {    std::unique_ptr<TObjectList> DataList(DoCollectWorkspace());    UnicodeString Name = WorkspaceName();    DoSaveWorkspace(      Name, DataList.get(),      !Configuration->DisablePasswordStoring &&      WinConfiguration->AutoSaveWorkspacePasswords, false);    WinConfiguration->LastStoredSession = Name;  }  AppLog(L"Closing main window");}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteDirViewRead(TObject * /*Sender*/){  TManagedTerminal * ManagedTerminal =    dynamic_cast<TManagedTerminal *>(RemoteDirView->Terminal);  if (ManagedTerminal != NULL)  {    ManagedTerminal->DirectoryLoaded = Now();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewSelectItem(TObject * Sender,  TListItem * /*Item*/, bool /*Selected*/){  TCustomDirView * DirView = reinterpret_cast<TCustomDirView *>(Sender);  switch (DirView->LastSelectMethod)  {    case smKeyboard:      Configuration->Usage->Inc(L"KeyboardSelections");      break;    case smMouse:      Configuration->Usage->Inc(L"MouseSelections");      break;  }}//---------------------------------------------------------------------------int __fastcall TCustomScpExplorerForm::AddSessionColor(TColor Color){  if (Color != 0)  {    return GetSessionColorImage(FSessionColors, Color, FSessionColorMaskImageIndex);  }  else  {    return FSessionTabImageIndex;  }}//---------------------------------------------------------------------------int __fastcall TCustomScpExplorerForm::AddFixedSessionImage(int GlyphsSourceIndex){  TPngImageCollectionItem * Item =    GlyphsModule->ExplorerImages->PngImages->Items[GlyphsSourceIndex];  FSessionColors->AddPng(Item->PngImage);  return FSessionColors->Count - 1;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::AddFixedSessionImages(){  FSessionColors->SetSize(GlyphsModule->ExplorerImages->Width, GlyphsModule->ExplorerImages->Height);  FNewRemoteTabTabImageIndex = AddFixedSessionImage(NonVisualDataModule->NewRemoteTabAction->ImageIndex);  FNewLocalTabTabImageIndex = AddFixedSessionImage(NonVisualDataModule->NewLocalTabAction->ImageIndex);  FSessionTabImageIndex = AddFixedSessionImage(SiteImageIndex);  FSessionColorMaskImageIndex = AddFixedSessionImage(SiteColorMaskImageIndex);  FLocalBrowserTabImageIndex = AddFixedSessionImage(LocalBrowserImageIndex);}//---------------------------------------------------------------------------int TCustomScpExplorerForm::GetNewTabActionImageIndex(){  return NonVisualDataModule->NewRemoteTabAction->ImageIndex;}//---------------------------------------------------------------------------int TCustomScpExplorerForm::GetNewTabTabImageIndex(TOperationSide Side){  switch (Side)  {    case osLocal:      return FNewLocalTabTabImageIndex;    case osRemote:    case osCurrent:      return FNewRemoteTabTabImageIndex;    default:      DebugFail();      return -1;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CollectItemsWithTextDisplayMode(TWinControl * Control){  for (int Index = 0; Index < Control->ControlCount; Index++)  {    TControl * AControl = Control->Controls[Index];    TWinControl * WinControl = dynamic_cast<TWinControl *>(AControl);    if (WinControl != NULL)    {      CollectItemsWithTextDisplayMode(WinControl);    }    TTBCustomToolbar * Toolbar = dynamic_cast<TTBCustomToolbar *>(AControl);    if (Toolbar != NULL)    {      // we care for top-level items only      TTBCustomItem * Items = Toolbar->Items;      for (int ItemIndex = 0; ItemIndex < Items->Count; ItemIndex++)      {        TTBCustomItem * Item = Items->Items[ItemIndex];        if (((Item->DisplayMode == nbdmImageAndText) ||             (dynamic_cast<TTBXLabelItem *>(Item) != NULL)) &&            EligibleForImageDisplayMode(Item))        {          FItemsWithTextDisplayMode.insert(Item);        }      }    }  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::EligibleForImageDisplayMode(TTBCustomItem * /*Item*/){  return true;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::UpdateToolbarDisplayMode(){  bool SelectiveToolbarText = WinConfiguration->SelectiveToolbarText;  TTBItemDisplayMode DisplayMode = (SelectiveToolbarText ? nbdmImageAndText : nbdmDefault);  typedef std::set<TTBCustomItem *> TItemsWithTextDisplayMode;  TItemsWithTextDisplayMode::iterator i = FItemsWithTextDisplayMode.begin();  bool Result = true;  while (Result && (i != FItemsWithTextDisplayMode.end()))  {    TTBCustomItem * Item = *i;    TTBXLabelItem * Label = dynamic_cast<TTBXLabelItem *>(Item);    if (Label != NULL)    {      // optimization      if (Label->Visible == SelectiveToolbarText)      {        Result = false;      }      else      {        Label->Visible = SelectiveToolbarText;      }    }    else    {      // optimization      if (Item->DisplayMode == DisplayMode)      {        Result = false;      }      else      {        Item->DisplayMode = DisplayMode;      }    }    ++i;  }  UpdateNewTabTab();  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DisplaySystemContextMenu(){  DebugFail();}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::IsBusy(){  // Among other, a lock level is non zero, while directory is being loaded,  // even when it happens as a result of dirview navigation,  // i.e. when TNonVisualDataModule is NOT FBusy.  // That's why the TNonVisualDataModule::GetBusy calls this method.  // Among other this prevents a panel auto update to occur while  // directory is changing.  return (FLockLevel > 0) || DirView(osCurrent)->IsEditing();}//---------------------------------------------------------------------------Boolean __fastcall TCustomScpExplorerForm::AllowedAction(TAction * Action, TActionAllowed Allowed){  // While the window is disabled, we still seem to process menu shortcuts at least,  // so stop it at least here.  // See also TCustomScpExplorerForm::RemoteDirViewBusy  bool Result;  if (Allowed == aaUpdate)  {    Result = true;  }  else  {    Result = !NonVisualDataModule->Busy;    if (Result && (Allowed == aaShortCut))    {      // Otherwise F5 for local-local will be swallowed by disabled local<>remote actions in TCustomScpExplorerForm::KeyDown      Action->Update();      Result = Action->Enabled;    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::EditMenuItemPopup(TTBCustomItem * Sender, bool FromLink){  NonVisualDataModule->EditMenuItemPopup(Sender, FromLink);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewBusy(TObject * /*Sender*/, int Busy, bool & State){  // This is somewhat redundant to LockWindow() call from  // TTerminalManager::TerminalReadDirectoryProgress.  // But disabling window is known not to block keyboard shorcuts  // (see TCustomScpExplorerForm::AllowedAction), this hopefully works.  if (Busy > 0)  {    if (NonVisualDataModule->Busy)    {      State = false;    }    else    {      NonVisualDataModule->StartBusy();      // Will be countered for TCustomDirView.DoExecute in DoDirViewExecFile      LockWindow();    }  }  else if (Busy < 0)  {    UnlockWindow();    NonVisualDataModule->EndBusy();  }  else  {    State = NonVisualDataModule->Busy;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsPageControlContextPopup(TObject * /*Sender*/, TPoint & MousePos, bool & Handled){  int Index = SessionsPageControl->IndexOfTabAt(MousePos.X, MousePos.Y);  if (Index >= 0)  {    TPopupMenu * PopupMenu = NULL;    TManagedTerminal * Session = GetSessionTabSession(SessionsPageControl->Pages[Index]);    if (Session != NULL)    {      SessionsPageControl->ActivePageIndex = Index;      if (DebugAlwaysTrue(SessionTabSwitched()))      {        // copied from TControl.WMContextMenu        SendCancelMode(SessionsPageControl);        // explicit popup instead of using PopupMenu property        // to avoid menu to popup somewhere within SessionTabSwitched above,        // while connecting yet not-connected session and hence        // allowing an access to commands over not-completely connected session        PopupMenu = Session->LocalBrowser ? NonVisualDataModule->LocalBrowserPopup : NonVisualDataModule->SessionsPopup;      }    }    else    {      if (SupportsLocalBrowser())      {        PopupMenu = NonVisualDataModule->NewTabPopup;      }    }    if (PopupMenu != NULL)    {      TPoint Point = SessionsPageControl->ClientToScreen(MousePos);      PopupMenu->PopupComponent = SessionsPageControl;      PopupMenu->Popup(Point.x, Point.y);    }  }  Handled = true;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanChangePassword(){  return HasActiveTerminal() && Terminal->IsCapable[fcChangePassword];}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ChangePassword(){  Configuration->Usage->Inc(L"PasswordChanges");  std::unique_ptr<TSessionData> ChangePasswordData(Terminal->SessionData->Clone());  ChangePasswordData->DisableAuthentationsExceptPassword();  ChangePasswordData->ChangePassword = true;  std::unique_ptr<TTerminal> ChangePasswordSession(    Terminal->CreateSecondarySession(L"ChangePassword", ChangePasswordData.get()));  ChangePasswordSession->AutoReadDirectory = false;  if (TTerminalManager::Instance()->ConnectTerminal(ChangePasswordSession.get()))  {    MessageDialog(MainInstructions(LoadStr(PASSWORD_CHANGED)), qtInformation, qaOK, HELP_CHANGE_PASSWORD);  }  else  {    Configuration->Usage->Inc(L"PasswordChangesFailed");  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::CanPrivateKeyUpload(){  // No nice way to assert SSH2  return HasActiveTerminal() && (Terminal->FSProtocol == cfsSFTP);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::PrivateKeyUpload(){  TOperationVisualizer OperationVisualizer;  UnicodeString FileName = Terminal->SessionData->PublicKeyFile;  TTerminalManager::Instance()->UploadPublicKey(Terminal, NULL, FileName);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::FormAfterMonitorDpiChanged(TObject *, int OldDPI, int NewDPI){  DebugUsedParam(OldDPI);  DebugAssert(NewDPI == GetControlPixelsPerInch(this));  GlyphsModule->PixelsPerInch = NewDPI;  // Can be called too early when primary monitor has non-system dpi  if (FSessionColors != NULL)  {    RegenerateSessionColorsImageList();  }  UpdateTabsSize();  UpdateSessionsPageControlHeight();  QueueFileListColumnAutoSize();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DockContextPopup(TObject * Sender, TPoint & MousePos, bool & /*Handled*/){  NonVisualDataModule->ControlContextPopup(Sender, MousePos);}//---------------------------------------------------------------------class TPublicControl : public TControl{friend class TCustomScpExplorerForm;};//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CopyPopup(TControl * DestControl, TControl * SourceControl){  static_cast<TPublicControl *>(DestControl)->PopupMenu = static_cast<TPublicControl *>(SourceControl)->PopupMenu;  static_cast<TPublicControl *>(DestControl)->OnContextPopup = static_cast<TPublicControl *>(SourceControl)->OnContextPopup;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DoBookmarkClick(TOperationSide Side, TObject * Sender){  TBookmark * Bookmark = DebugNotNull(reinterpret_cast<TBookmark *>(dynamic_cast<TTBCustomItem *>(Sender)->Tag));  OpenBookmark(Side, Bookmark);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::LocalBookmarkClick(TObject * Sender){  DoBookmarkClick(osLocal, Sender);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteBookmarkClick(TObject * Sender){  DoBookmarkClick(osRemote, Sender);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CreateOpenDirMenuList(  TTBCustomItem * Menu, TOperationSide Side, TBookmarkList * BookmarkList){  if (BookmarkList != NULL)  {    TNotifyEvent OnBookmarkClick = (Side == osLocal) ? &LocalBookmarkClick : &RemoteBookmarkClick;    if (IsLocalBrowserMode())    {      Side = osLocal;    }    if (!WinConfiguration->UseLocationProfiles)    {      std::unique_ptr<TStringList> Directories(new TStringList());      Directories->CaseSensitive = (Side == osRemote);      for (int Index = 0; Index < BookmarkList->Count; Index++)      {        TBookmark * Bookmark = BookmarkList->Bookmarks[Index];        UnicodeString Directory = Bookmark->GetSideDirectory(Side);        if (!Directory.IsEmpty() && (Directories->IndexOf(Directory) < 0))        {          std::unique_ptr<TTBCustomItem> Item(new TTBXItem(Owner));          Item->Caption = EscapeHotkey(Directory);          Item->ShortCut = Bookmark->ShortCut;          Item->OnClick = OnBookmarkClick;          Item->Tag = reinterpret_cast<int>(Bookmark);          Directories->Add(Directory);          Menu->Add(Item.release());        }      }    }    else    {      std::unique_ptr<TStrings> Folders(CreateSortedStringList());      for (int Index = 0; Index < BookmarkList->Count; Index++)      {        TBookmark * Bookmark = BookmarkList->Bookmarks[Index];        if (!Bookmark->Node.IsEmpty())        {          Folders->Add(Bookmark->Node);        }      }      for (int Index = 0; Index < Folders->Count; Index++)      {        std::unique_ptr<TTBCustomItem> Item(new TTBXSubmenuItem(Owner));        Item->Caption = Folders->Strings[Index];        Item->ImageIndex = NonVisualDataModule->RemoteChangePathAction2->ImageIndex;        Folders->Objects[Index] = Item.get();        Menu->Add(Item.release());      }      for (int Index = 0; Index < BookmarkList->Count; Index++)      {        TBookmark * Bookmark = BookmarkList->Bookmarks[Index];        TTBCustomItem * Parent;        if (!Bookmark->Node.IsEmpty())        {          DebugAssert(Folders->IndexOf(Bookmark->Node) >= 0);          Parent = dynamic_cast<TTBCustomItem *>(Folders->Objects[Folders->IndexOf(Bookmark->Node)]);        }        else        {          Parent = Menu;        }        std::unique_ptr<TTBCustomItem> Item(new TTBXItem(Owner));        Item->Caption = Bookmark->Name;        Item->ShortCut = Bookmark->ShortCut;        Item->OnClick = OnBookmarkClick;        Item->Tag = reinterpret_cast<int>(Bookmark);        if (((Bookmark->Name == Bookmark->Local) || (Bookmark->Name == Bookmark->Remote)) &&            (Bookmark->Local.IsEmpty() || Bookmark->Remote.IsEmpty()))        {          // No hint for location profiles that are actually mere "bookmarks"        }        else        {          UnicodeString Hint = FORMAT(LoadStrPart(LOCATION_PROFILE_HINT, 1), (Bookmark->Name));          UnicodeString LongHint;          if (!Bookmark->Local.IsEmpty())          {            AddToList(LongHint, FORMAT(LoadStrPart(LOCATION_PROFILE_HINT, 2), (Bookmark->Local)), L"\n");          }          if (!Bookmark->Remote.IsEmpty())          {            AddToList(LongHint, FORMAT(LoadStrPart(LOCATION_PROFILE_HINT, 3), (Bookmark->Remote)), L"\n");          }          AddToList(Hint, LongHint, L"|");          Item->Hint = Hint;        }        Parent->Add(Item.release());      }    }    AddMenuSeparator(Menu);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CreateOpenDirMenu(TTBCustomItem * Menu, TOperationSide Side){  Menu->Clear();  std::unique_ptr<TTBCustomItem> Item;  Item.reset(new TTBXItem(Owner));  Item->Action = (Side == osLocal) ? NonVisualDataModule->LocalOpenDirAction : NonVisualDataModule->RemoteOpenDirAction;  Item->Options = Item->Options << tboDefault;  Menu->Add(Item.release());  AddMenuSeparator(Menu);  if (Terminal != NULL)  {    CreateOpenDirMenuList(Menu, Side, WinConfiguration->Bookmarks[Terminal->SessionData->SessionKey]);  }  CreateOpenDirMenuList(Menu, Side, WinConfiguration->SharedBookmarks);  Item.reset(new TTBXItem(Owner));  Item->Action = (Side == osLocal) ? NonVisualDataModule->LocalAddBookmarkAction2 : NonVisualDataModule->RemoteAddBookmarkAction2;  Menu->Add(Item.release());}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::TryOpenDirectory(TOperationSide Side, const UnicodeString & Path){  bool Result = true;  bool Remote = !IsSideLocalBrowser(Side);  try  {    UnicodeString APath = Path;    if (Remote)    {      Terminal->ExceptionOnFail = true;    }    else    {      APath = ExpandEnvironmentVariables(Path);    }    try    {      DirView(Side)->Path = APath;    }    __finally    {      if (Remote)      {        Terminal->ExceptionOnFail = false;      }    }  }  catch (Exception & E)  {    if (!Remote || Terminal->Active)    {      ShowExtendedExceptionEx(Terminal, &E);      Result = false;    }    else    {      throw;    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ReloadDirectory(TOperationSide Side){  // Make sure there some feedback even when loading tiny local folders  TInstantOperationVisualizer Visualizer;  DirView(Side)->ReloadDirectory();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CloseSessionTab(int Index){  if (Index == SessionsPageControl->TabIndex)  {    CloseTab();  }  else  {    TTabSheet * TabSheet = SessionsPageControl->Pages[Index];    TTerminal * Terminal = GetSessionTabSession(TabSheet);    TTerminalManager * Manager = TTerminalManager::Instance();    if (!Terminal->Active)    {      Manager->FreeTerminal(Terminal);    }    else    {      TTerminalQueue * Queue = Manager->FindQueueForTerminal(Terminal);      if (CanCloseQueue(Queue))      {        Manager->FreeTerminal(Terminal);      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsPageControlTabButtonClick(TPageControl *, int Index){  TManagedTerminal * Session = GetSessionTabSession(SessionsPageControl->Pages[Index]);  if (Session == NULL)  {    TRect ButtonRect = SessionsPageControl->TabButtonRect(Index);    ButtonRect = TRect(SessionsPageControl->ClientToScreen(ButtonRect.TopLeft()), SessionsPageControl->ClientToScreen(ButtonRect.BottomRight()));    //TPoint P = TPoint(ButtonRect.Left, ButtonRect.Bottom);    //P = SessionsPageControl->ClientToScreen(P);    MenuPopup(NonVisualDataModule->NewTabPopup, ButtonRect, SessionsPageControl);  }  else  {    CloseSessionTab(Index);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CopyFilesToClipboard(TOperationSide Side, bool OnFocused){  if (DebugAlwaysTrue(!IsSideLocalBrowser(Side)))  {    TInstantOperationVisualizer Visualizer;    // To trigger ClipboardDataObjectRelease (in case the clipboard already contains our data)    // before we create a new data object    ClipboardClear();    DebugAssert(FClipboardFakeDirectory.IsEmpty());    DebugAssert(FClipboardFakeMonitors.get() == NULL);    FClipboardFakeDirectory = CreateFakeTransferDirectory();    // Intermediate variable to WORKAROUND a crash in compiler    TObjectList * ClipboardFakeMonitors =      StartCreationDirectoryMonitorsOnEachDrive(FILE_NOTIFY_CHANGE_DIR_NAME, ClipboardFakeCreated);    FClipboardFakeMonitors.reset(ClipboardFakeMonitors);    if (FClipboardDragDropFilesEx.get() == NULL)    {      FClipboardDragDropFilesEx.reset(new TDragDropFilesEx(this));      FClipboardDragDropFilesEx->OnDataObjectRelease = ClipboardDataObjectRelease;    }    FClipboardDragDropFilesEx->FileList->Clear();    FClipboardDragDropFilesEx->FileList->AddItem(NULL, FClipboardFakeDirectory);    FClipboardDragDropFilesEx->CopyToClipboard();    FClipboardTerminal = Terminal;    // Need full paths, as cwd can be different once files are pasted    FClipboardFileList.reset(TRemoteFileList::CloneStrings(RemoteDirView->CreateFileList(OnFocused, true)));    for (int Index = 0; Index < FClipboardFileList->Count; Index++)    {      FClipboardFileList->Strings[Index] = UnixExcludeTrailingBackslash(FClipboardFileList->Strings[Index]);    }    AppLogFmt(L"Created fake clipboard directory \"%s\" and started drive monitors", (FClipboardFakeDirectory));  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ClipboardClear(){  if (OpenClipboard(0))  {    AppLog(L"Clearing clipboard");    EmptyClipboard(); // Calls ClipboardDataObjectRelease, if clipboard contains our data    CloseClipboard();  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::DoesClipboardContainOurFiles(){  return !FClipboardFakeDirectory.IsEmpty();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ClipboardStop(){  bool Deleted = RemoveDir(ApiPath(FClipboardFakeDirectory));  AppLogFmt(L"Clearing clipboard, deleted clipboard temporary folder \"%s\" - %d", (FClipboardFakeDirectory, int(Deleted)));  FClipboardFakeDirectory = UnicodeString();  FClipboardTerminal = NULL;  if (FDownloadingFromClipboard)  {    // We are called by the monitor, so attempt to release it would deadlock    FClipboardFakeMonitorsPendingReset = true;  }  else  {    FClipboardFakeMonitors.reset(NULL);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ClipboardDataObjectRelease(TObject * /*Sender*/){  if (DebugAlwaysTrue(!FClipboardFakeDirectory.IsEmpty()))  {    ClipboardStop();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ClipboardDownload(const UnicodeString & TargetDirectory, bool NoConfirmation, bool DragDrop){  TTerminalManager * Manager = TTerminalManager::Instance();  Manager->ActiveSession = FClipboardTerminal;  TTransferOperationParam Params;  Params.TargetDirectory = TargetDirectory;  Params.DragDrop = DragDrop;  ExecuteFileOperation(foCopy, osRemote, FClipboardFileList.get(), NoConfirmation, &Params);}//---------------------------------------------------------------------------void TCustomScpExplorerForm::PasteFiles(){  // Guard against possible race conditions  if (!FClipboardPasteTarget.IsEmpty())  {    // ClipboardFakeCreated might be called while we are here, so make sure we finish operating on the same path we started with    UnicodeString Target = FClipboardPasteTarget;    FClipboardPasteTarget = EmptyStr;    // Can fail as it can be e.g. locked by AV, so we retry that later    bool Removed = RemoveDir(ApiPath(Target));    AppLogFmt(L"First attempt to delete pasted fake clipboard directory \"%s\" - %d", (Target, int(Removed)));    try    {      if (NonVisualDataModule->Busy)      {        AppLog(L"Is busy, cannot paste");      }      else      {        DebugAssert(!FClipboardFakeMonitorsPendingReset);        FClipboardFakeMonitorsPendingReset = false;        bool NoConfirmation = (WinConfiguration->DDTransferConfirmation == asOff);        TAutoFlag Flag(FDownloadingFromClipboard);        AppLog(L"Downloading to paste target...");        ClipboardDownload(ExtractFilePath(Target), NoConfirmation, true);        AppLog(L"Downloaded to paste target...");      }    }    __finally    {      if (!Removed)      {        Removed = RemoveDir(ApiPath(Target));        AppLogFmt(L"Second attempt to delete pasted fake clipboard directory \"%s\" - %d", (Target, int(Removed)));      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ClipboardFakeCreated(TObject * /*Sender*/, const UnicodeString FileName){  // It can actually rarelly happen that some random file is created, while we are shutting down the monitor  // (as it pumps a Windows message queue while being shutted down)  if (DebugAlwaysTrue(!FClipboardFakeDirectory.IsEmpty()) &&      // Is can happen that creation of our temporary directory is detected (even though we are creating it before starting the monitors).      // It tent do happen with later copy-pastes, probably because everything is cached already and monitors start quickly.      !IsPathToSameFile(FClipboardFakeDirectory, FileName) &&      SameText(ExtractFileName(FileName), ExtractFileName(FClipboardFakeDirectory)))  {    AppLogFmt(L"Fake clipboard directory pasted to \"%s\"", (FileName));    FClipboardPasteTarget = FileName;    // Particularly when pasting to external HDD, the fake directory is strangely recreated if removed here in the monitor callback.    // Postponing removing (or actually whole pasting operation) seems to help.    PostMessage(Handle, WM_PASTE_FILES, 0, 0);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewGetItemColor(  TObject * Sender, UnicodeString FileName, bool Directory, __int64 Size, TDateTime Modification, TColor & Color){  TFileMasks::TParams MaskParams;  MaskParams.Size = Size;  MaskParams.Modification = Modification;  TCustomDirView * DirView = DebugNotNull(dynamic_cast<TCustomDirView *>(Sender));  bool Local = (dynamic_cast<TUnixDirView *>(DirView) == NULL);  // TUnixDirView::ItemFullFileName returns trailing backslash for directories, what filemask cannot deal with  if (!Local && Directory)  {    FileName = UnixExcludeTrailingBackslash(FileName);  }  for (TFileColorData::TList::const_iterator Iter = FFileColors.begin(); Iter != FFileColors.end(); Iter++)  {    bool ImplicitMatch;    if (Iter->FileMask.Matches(FileName, Local, Directory, &MaskParams, false, ImplicitMatch) &&        !ImplicitMatch)    {      Color = Iter->Color;      break;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewKeyDown(TObject * Sender, WORD & Key, TShiftState){  TCustomDirView * DirView = dynamic_cast<TCustomDirView *>(Sender);  if (!DirView->IsEditing())  {    // Handled here, instead of RemoteDirViewKeyPress (as on Login dialog),    // as VK_BACK is handled by TCustomDirView.KeyDown and we can swallow it here,    // while searching    if (Key == VK_BACK)    {      if (FIncrementalSearchState.Searching)      {        if (FIncrementalSearchState.Text.Length() <= 1)        {          ResetIncrementalSearch();        }        else        {          UnicodeString NewText = LeftStr(FIncrementalSearchState.Text, FIncrementalSearchState.Text.Length() - 1);          IncrementalSearch(NewText, false, false);        }        Key = 0;      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewKeyPress(TObject * Sender, wchar_t & Key){  TCustomDirView * DirView = dynamic_cast<TCustomDirView *>(Sender);  if (!DirView->IsEditing() && (WinConfiguration->PanelSearch != isOff))  {    // Filter control sequences.    // When not searching yet, prefer use of the space for toggling file selection    // (so we cannot incrementally search for a string starting with a space).    if ((Key > VK_SPACE) ||        ((Key == VK_SPACE) && (GetKeyState(VK_CONTROL) >= 0) && !FIncrementalSearchState.Searching))    {      IncrementalSearch(FIncrementalSearchState.Text + Key, false, false);      Key = 0;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ResetIncrementalSearch(){  if (FIncrementalSearchState.Searching)  {    FIncrementalSearchState.Reset();    DirView(osCurrent)->UpdateStatusBar();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::IncrementalSearch(const UnicodeString & Text, bool SkipCurrent, bool Reverse){  TListItem * Item = SearchFile(Text, SkipCurrent, Reverse);  if (Item == NULL)  {    MessageBeep(MB_ICONHAND);  }  else  {    TCustomDirView * ADirView = DirView(osCurrent);    {      TAutoNestingCounter Guard(FIncrementalSearching);      ADirView->FocusItem(Item);      if (ADirView->NortonLike == nlOff)      {        if ((ADirView->Selected != Item) ||            (ADirView->SelCount > 1))        {          ADirView->ClearSelection();          ADirView->Selected = Item;        }      }    }    FIncrementalSearchState.Searching = true;    FIncrementalSearchState.Text = Text;    Item->MakeVisible(false);    TListItem * NextItem = SearchFile(Text, true, Reverse);    FIncrementalSearchState.HaveNext = (NextItem != NULL) && (NextItem != Item);    ADirView->UpdateStatusBar();  }}//---------------------------------------------------------------------------TListItem * __fastcall TCustomScpExplorerForm::GetNextFile(TListItem * Item, bool Reverse){  int Index = Item->Index;  if (!Reverse)  {    Index++;    if (Index >= Item->Owner->Count)    {      Index = 0;    }  }  else  {    Index--;    if (Index < 0)    {      Index = Item->Owner->Count - 1;    }  }  return Item->Owner->Item[Index];}//---------------------------------------------------------------------------TListItem * __fastcall TCustomScpExplorerForm::SearchFile(const UnicodeString & Text, bool SkipCurrent, bool Reverse){  TCustomDirView * ADirView = DirView(osCurrent);  if (ADirView->Items->Count == 0)  {    return NULL;  }  else  {    TListItem * CurrentItem = (ADirView->ItemFocused != NULL) ? ADirView->ItemFocused : ADirView->Items->Item[0];    TListItem * Item = CurrentItem;    if (SkipCurrent)    {      Item = DebugNotNull(GetNextFile(Item, Reverse));    }    while (true)    {      bool Matches = false;      switch (WinConfiguration->PanelSearch)      {        case isNameStartOnly:          Matches = ContainsTextSemiCaseSensitive(ADirView->ItemFileName(Item).SubString(1, Text.Length()), Text);          break;        case isName:          Matches = ContainsTextSemiCaseSensitive(ADirView->ItemFileName(Item), Text);          break;        case isAll:          int ColCount = (ADirView->DirViewStyle == dvsReport) ? ADirView->ColProperties->Count : 1;          int Index = 0;          while ((Index < ColCount) && !Matches)          {            bool Visible = (ADirView->DirViewStyle == dvsReport) ? ADirView->ColProperties->Visible[Index] : true;            if (Visible)            {              Matches = ContainsTextSemiCaseSensitive(ADirView->GetColumnText(Item, Index), Text);            }            Index++;          }          break;      }      if (Matches)      {        return Item;      }      Item = GetNextFile(Item, Reverse);      if (Item == CurrentItem)      {        return NULL;      }    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewExit(TObject *){  ResetIncrementalSearch();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CMDialogKey(TWMKeyDown & Message){  if (Message.CharCode == VK_TAB)  {    if (!FIncrementalSearchState.Text.IsEmpty())    {      TShiftState Shift = KeyDataToShiftState(Message.KeyData);      bool Reverse = Shift.Contains(ssShift);      IncrementalSearch(FIncrementalSearchState.Text, true, Reverse);      Message.Result = 1;      return;    }  }  else if (Message.CharCode == VK_ESCAPE)  {    if (FIncrementalSearchState.Searching)    {      ResetIncrementalSearch();      Message.Result = 1;      return;    }  }  TForm::Dispatch(&Message);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::Deactivate(){  TForm::Deactivate();  // E.g. when switching to an internal editor window  ResetIncrementalSearch();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ApplicationEventsDeactivate(TObject *){  // When switching to another application  ResetIncrementalSearch();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::ApplicationEventsModalBegin(TObject *){  ResetIncrementalSearch();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirViewChangeFocus(TObject *, TListItem *){  if (FIncrementalSearching <= 0)  {    ResetIncrementalSearch();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteStatusBarMouseDown(TObject *, TMouseButton, TShiftState, int, int){  CountClicksForWindowPrint(this);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteDirViewResize(TObject *){  CenterReconnectToolbar();}//---------------------------------------------------------------------------void TCustomScpExplorerForm::DoBrowseFile(TCustomDirView * DirView, const UnicodeString & FileName){  if (!FileName.IsEmpty())  {    DirView->FocusByName(FileName);    if (DirView->ItemFocused != NULL)    {      DirView->ItemFocused->Selected = true;    }  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::BrowseFile(const UnicodeString & FileName){  DoBrowseFile(RemoteDirView, FileName);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::UpdateQueueFileList(){  if (!FQueueStatusUpdating)  {    bool Refresh;    if ((FQueueStatus != NULL) && QueueFileList->Visible)    {      Refresh = FQueueStatus->UpdateFileList(FQueueController->GetFocusedPrimaryItem(), FQueueFileList.get());    }    else    {      if (FQueueFileList->GetCount() > 0)      {        FQueueFileList->Clear();        Refresh = true;      }    }    int Count = FQueueFileList->GetCount();    if (QueueFileList->Items->Count != Count)    {      DebugAssert(Refresh);      QueueFileList->Items->Count = Count;    }    if (Refresh)    {      QueueFileList->Invalidate();    }    DebugAssert(QueueFileList->Items->Count == FQueueFileList->GetCount());  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueFileListData(TObject *, TListItem * Item){  Item->Caption = FQueueFileList->GetFileName(Item->Index);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueView3Change(TObject *, TListItem *, TItemChange){  // Should be improved, once we do not refresh the list when switching between details of the same batch.  // See TSynchronizeChecklistDialog::UpdateTimer  if (QueueFileList->Items->Count > 0)  {    QueueFileList->Items->Item[0]->MakeVisible(false);  }  UpdateQueueFileList();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueLabelGetStatus(TCustomPathLabel *, bool & Active){  Active = QueueView3->Focused() || QueueFileList->Focused();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueFileListEnterExit(TObject *){  QueueLabelUpdateStatus();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueFileListCustomDrawItem(  TCustomListView * Sender, TListItem * Item, TCustomDrawState, bool & DebugUsedArg(DefaultDraw)){  int State = FQueueFileList->GetState(Item->Index);  if (State == qfsProcessed)  {    Sender->Canvas->Font->Color = clGrayText;  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueFileListColumnAutoSize(){  // We do not really need whole width, so we always preemptivelly keep free space for the vertical scrollbar  QueueFileList->Column[0]->Width =    QueueFileList->ClientWidth - GetSystemMetricsForControl(QueueFileList, SM_CXVSCROLL) - ScaleByTextHeight(QueueFileList, 8);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::QueueFileListResize(TObject *){  QueueFileListColumnAutoSize();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::CloseApp(){  // Called from TNonVisualDataModule::ExplorerActionsExecute, which sets busy flag.  // FormCloseQuery must check busy state, so that the application cannot be closed while busy by Alt+F4 and X button.  // So we clear the flag here.  DebugAssert(NonVisualDataModule->Busy);  NonVisualDataModule->EndBusy();  try  {    Close();  }  __finally  {    NonVisualDataModule->StartBusy();  }}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::IsActiveTerminal(TTerminal * Terminal){  return (Terminal != NULL) && Terminal->Active;}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::HasManagedSession(){  return (ManagedSession != NULL);}//---------------------------------------------------------------------------bool __fastcall TCustomScpExplorerForm::HasActiveTerminal(){  return IsActiveTerminal(Terminal);}//---------------------------------------------------------------------------void TCustomScpExplorerForm::LocalLocalCopy(  TFileOperation, TOperationSide, bool DebugUsedArg(OnFocused), bool DebugUsedArg(NoConfirmation),  bool DebugUsedArg(DragDrop), unsigned int DebugUsedArg(Flags)){  DebugFail();}//---------------------------------------------------------------------------void TCustomScpExplorerForm::LocalLocalCopyCommand(TFileOperation Operation, TOperationSide Side, bool OnFocused, unsigned int Flags){  LocalLocalCopy(Operation, Side, OnFocused, !WinConfiguration->ConfirmTransferring, false, Flags);}//---------------------------------------------------------------------------void TCustomScpExplorerForm::UpdateTabsSize(){  // 1) Changing tab list triggers the OnResize.  // 2) Is called in TForm constructor, when we are not ready to call SessionListChanged (particularly when starting with colored session)  if (!FUpdatingSessionTabs && (FSessionColors != NULL))  {    // UpdateTabsCaptionTruncation should be enough    SessionListChanged(true);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsPageControlResize(TObject *){  UpdateTabsSize();}//---------------------------------------------------------------------------UnicodeString TCustomScpExplorerForm::GetSessionPath(TManagedTerminal * ASession, TOperationSide Side){  if (ASession == ManagedSession)  {    UpdateSession(ASession);  }  TSessionData * Data = ASession->StateData;  UnicodeString Result;  if (Side == osLocal)  {    Result = Data->LocalDirectory;  }  else if (DebugAlwaysTrue(Side == osOther))  {    Result = ASession->LocalBrowser ? Data->OtherLocalDirectory : Data->RemoteDirectory;  }  return Result;}//---------------------------------------------------------------------------UnicodeString TCustomScpExplorerForm::GetTabHintSessionDetails(TManagedTerminal * ASession){  UnicodeString Title = TTerminalManager::Instance()->GetSessionTitle(ASession, false);  UnicodeString Result = ASession->SessionData->DefaultSessionName;  if (Title == Result)  {    Result = EmptyStr;  }  else  {    Result += L"\n";  }  return Result;}//---------------------------------------------------------------------------UnicodeString TCustomScpExplorerForm::GetTabHintDetails(TManagedTerminal * ASession){  UnicodeString Result = GetTabHintSessionDetails(ASession);  if (!ASession->Active)  {    Result += LoadStr(STATUS_NOT_CONNECTED2);  }  else  {    Result += GetSessionPath(ASession, osRemote);  }  return Result;}//---------------------------------------------------------------------------UnicodeString TCustomScpExplorerForm::GetNewTabHintDetails(){  return LoadStr(NEW_REMOTE_TAB_HINT);}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::SessionsPageControlTabHint(TPageControl *, int Index, UnicodeString & Hint){  if (Index >= 0)  {    TThemeTabSheet * TabSheet = SessionsPageControl->Pages[Index];    TManagedTerminal * TabSession = GetSessionTabSession(TabSheet);    if (TabSession == NULL)    {      UnicodeString NewTabTabCaption = GetNewTabTabCaption();      if (NewTabTabCaption != TabSheet->Caption)      {        Hint = NewTabTabCaption + L"|" + GetNewTabHintDetails();      }    }    else    {      TTerminalManager * Manager = TTerminalManager::Instance();      UnicodeString TabCaption = Manager->GetSessionTitle(TabSession, true);      Hint = TabCaption + L"|" + GetTabHintDetails(TabSession);    }  }}//---------------------------------------------------------------------------typedef std::vector<TListItem *> TListItemsVector;struct TCalculateSizeOperation{  TCalculateSizeStats Stats;  TListItemsVector ListItems;  size_t Index;};//---------------------------------------------------------------------------void TCustomScpExplorerForm::CalculateDirectorySizes(TOperationSide Side){  TCalculateSizeOperation CalculateSizeOperation;  Side = GetSide(Side);  TCustomDirView * ADirView = DirView(Side);  bool LocalSide = IsSideLocalBrowser(Side);  std::unique_ptr<TStrings> AllFileList(ADirView->CreateFileList(false, LocalSide, NULL, true));  std::unique_ptr<TStrings> FileList(new TStringList());  for (int Index = 0; Index < AllFileList->Count; Index++)  {    TListItem * Item = DebugNotNull(dynamic_cast<TListItem *>(AllFileList->Objects[Index]));    if (ADirView->ItemIsDirectory(Item))    {      FileList->AddObject(AllFileList->Strings[Index], ADirView->ItemData(Item));      CalculateSizeOperation.ListItems.push_back(Item);    }  }  CalculateSizeOperation.Index = 0;  __int64 Size = 0;  TValueRestorer<TCalculateSizeOperation *> DirectorySizeOperationRestorer(FCalculateSizeOperation, &CalculateSizeOperation);  TValueRestorer<TFileOperationFinishedEvent> OnFileOperationFinishedRestorer(FOnFileOperationFinished);  FOnFileOperationFinished = DirectorySizeCalculated;  TValueRestorer<TFileOperation> PrimaryOperationRestorer(FPrimaryOperation, foCalculateSize);  TCalculatedSizes CalculatedSizes;  CalculateSizeOperation.Stats.CalculatedSizes = &CalculatedSizes;  if (LocalSide)  {    TValueRestorer<TOperationSide> ProgressSideRestorer(FProgressSide, Side);    ManagedSession->CalculateLocalFilesSize(FileList.get(), Size, NULL, true, NULL, &CalculatedSizes);  }  else  {    TCalculateSizeParams Params;    Params.Stats = &CalculateSizeOperation.Stats;    Params.UseCache = true;    Terminal->CalculateFilesSize(FileList.get(), Size, Params);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::DirectorySizeCalculated(TOperationSide Side, const UnicodeString & FileName, bool Success){  DebugAlwaysTrue(FCalculateSizeOperation != NULL);  TListItem * Item = VisualiseOperationFinished(Side, FileName, false);  TCustomDirView * ADirView = dynamic_cast<TCustomDirView *>(Item->Owner->Owner);  // optimization  bool GotExpectedItem =    (FCalculateSizeOperation->Index < FCalculateSizeOperation->ListItems.size()) &&    (FCalculateSizeOperation->ListItems[FCalculateSizeOperation->Index] == Item);  int Index = -1;  if (DebugAlwaysTrue(GotExpectedItem))  {    Index = FCalculateSizeOperation->Index;    FCalculateSizeOperation->Index++;  }  else  {    TListItemsVector::iterator I =      std::find(FCalculateSizeOperation->ListItems.begin(), FCalculateSizeOperation->ListItems.end(), Item);    if (DebugAlwaysTrue(I != FCalculateSizeOperation->ListItems.end()))    {      Index = I - FCalculateSizeOperation->ListItems.begin();    }  }  if (DebugAlwaysTrue(Index >= 0) && Success)  {    __int64 Size = (*FCalculateSizeOperation->Stats.CalculatedSizes)[Index];    ADirView->SetItemCalculatedSize(Item, Size);  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::MessageDockRequestDock(TObject *, TTBCustomDockableWindow *, bool & Accept){  Accept = false;}//---------------------------------------------------------------------------void TCustomScpExplorerForm::AutoSizeColumns(TOperationSide Side){  // Send Ctrl+Gray+ to the list view  TKeyboardState KeyState;  GetKeyboardState(KeyState);  TKeyboardState NewKeyState;  memset(NewKeyState, 0, sizeof(NewKeyState));  NewKeyState[VK_CONTROL] = 0x81;  SetKeyboardState(NewKeyState);  SendMessage(DirView(Side)->Handle, WM_KEYDOWN, VK_ADD, 0);  SetKeyboardState(KeyState);}//---------------------------------------------------------------------------void TCustomScpExplorerForm::QueueResetLayoutColumns(){  LoadListViewStr(QueueView3, QueueViewLayoutDefault);}//---------------------------------------------------------------------------void * TCustomScpExplorerForm::SaveFocus(){  return NULL;}//---------------------------------------------------------------------------void TCustomScpExplorerForm::RestoreFocus(void * Focus){  DebugUsedParam(Focus);  DebugAssert(Focus == NULL);}//---------------------------------------------------------------------------void TCustomScpExplorerForm::IncrementalSearchStart(){  TCustomDirView * ADirView = DirView(osCurrent);  ADirView->SetFocus();  if (!FIncrementalSearchState.Searching)  {    FIncrementalSearchState.Searching = true;    FIncrementalSearchState.HaveNext = false;    DebugAssert(FIncrementalSearchState.Text.IsEmpty());    ADirView->UpdateStatusBar();  }}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteDirViewThumbnailNeeded(  TUnixDirView *, TListItem * Item, TRemoteFile * File, const TSize & Size, TBitmap *& Bitmap){  // though when downloading to temporary folder, encryption should not be a problem  if (Terminal->IsCapable[fcBackgroundTransfers] &&      !File->IsDirectory)  {    UnicodeString FileName = File->FullFileName;    TFileMasks::TParams MaskParams;    MaskParams.Size = File->Size;    MaskParams.Modification = File->Modification;    if ((File->Size <= static_cast<__int64>(WinConfiguration->RemoteThumbnailSizeLimit) * 1024) &&        FRemoteThumbnailMask.Matches(FileName, false, File->IsDirectory, &MaskParams))    {      Bitmap = TTerminalManager::Instance()->ThumbnailNeeded(Terminal, Item->Index, File, Size);    }  }}//---------------------------------------------------------------------------TThumbnailDownloadQueueItem * TCustomScpExplorerForm::AddThumbnailDownloadQueueItem(TManagedTerminal * ATerminal){  DebugAssert(ATerminal == Terminal);  TGUICopyParamType CopyParam = GUIConfiguration->CurrentCopyParam;  TemporaryFileCopyParam(CopyParam);  CopyParam.TransferMode = tmBinary;  UnicodeString SourceDir = ATerminal->CurrentDirectory;  UnicodeString TempDir, RootTempDir;  TemporaryDirectoryForRemoteFiles(SourceDir, CopyParam, true, TempDir, RootTempDir);  TTerminalQueue * AQueue = TTerminalManager::Instance()->FindQueueForTerminal(ATerminal);  DebugAssert((Queue == NULL) || (AQueue == Queue)); // we might get here before queue is set  TThumbnailDownloadQueueItem * QueueItem =    new TThumbnailDownloadQueueItem(this, Terminal, SourceDir, TempDir, &CopyParam);  AddQueueItem(AQueue, QueueItem, ATerminal);  return QueueItem;}//---------------------------------------------------------------------------enum { qccRemoteItemVisible, qccRemoteItemRedraw };typedef std::pair<int, UnicodeString> TRemoteItemVisibleData;//---------------------------------------------------------------------------void TCustomScpExplorerForm::PostThumbnailVisibleQueueQuery(int Index, const UnicodeString & FileName){  // The queue might be destroyed before the WM_QUEUE_CALLBACK is processed  TRemoteItemVisibleData * Data = new TRemoteItemVisibleData();  Data->first = Index;  Data->second = FileName;  PostMessage(Handle, WM_QUEUE_CALLBACK, qccRemoteItemVisible, reinterpret_cast<WPARAM>(Data));}//---------------------------------------------------------------------------void TCustomScpExplorerForm::PostThumbnailDrawRequest(int Index){  PostMessage(Handle, WM_QUEUE_CALLBACK, qccRemoteItemRedraw, Index);}//---------------------------------------------------------------------------void TCustomScpExplorerForm::WMQueueCallback(TMessage & Message){  int Command = Message.WParam;  if (Command == qccRemoteItemVisible)  {    TRemoteItemVisibleData * Data = reinterpret_cast<TRemoteItemVisibleData *>(Message.LParam);    int Index = Data->first;    UnicodeString FileName = Data->second;    delete Data;    TGuard Guard(Terminal->ThumbnailsSection.get());    bool Visible = False;    if (Terminal->ThumbnailsEnabled &&        // though we should better also disable thumbnails once we switch to different view style        (RemoteDirView->DirViewStyle == dvsThumbnail))    {      // The message might be processed, while we are already loading a different directory      if ((Index >= 0) &&          (Index < RemoteDirView->Items->Count))      {        TListItem * Item = RemoteDirView->Items->Item[Index];        Visible =          (RemoteDirView->ItemFullFileName(Item) == FileName) &&          ListView_IsItemVisible(RemoteDirView->Handle, Index);      }    }    Terminal->ThumbnailVisible(Index, FileName, Visible);  }  else if (Command == qccRemoteItemRedraw)  {    int Index = Message.LParam;    if ((Index >= 0) &&        (Index < RemoteDirView->Items->Count))    {      RemoteDirView->InvalidateItem(RemoteDirView->Items->Item[Index]);    }  }}//---------------------------------------------------------------------------void TCustomScpExplorerForm::InitializeRemoteThumbnailMask(){  UnicodeString DefaultRemoteThumbnailMask = L"*.jpg;*.jpeg;*.gif;*.png;*.svg;*.bmp;*.raw;*.ico;*.heic";  UnicodeString RemoteThumbnailMask = WinConfiguration->RemoteThumbnailMask;  if (RemoteThumbnailMask.IsEmpty() ||      StartsStr(L"+", RemoteThumbnailMask) || StartsStr(L"-", RemoteThumbnailMask) || StartsStr(L"*", RemoteThumbnailMask))  {    std::unique_ptr<TStrings> RemoteThumbnailMasks(new TStringList());    while (!DefaultRemoteThumbnailMask.IsEmpty())    {      RemoteThumbnailMasks->Add(CutToChar(DefaultRemoteThumbnailMask, L';', true));    }    RemoteThumbnailMasks.reset(ProcessFeatures(RemoteThumbnailMasks.get(), RemoteThumbnailMask));    RemoteThumbnailMask = EmptyStr;    for (int Index = 0; Index < RemoteThumbnailMasks->Count; Index++)    {      AddToList(RemoteThumbnailMask, RemoteThumbnailMasks->Strings[Index], L";");    }  }  FRemoteThumbnailMask.Masks = RemoteThumbnailMask;}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteDirViewStartLoading(TObject *){  Terminal->StartLoadingDirectory();}//---------------------------------------------------------------------------void __fastcall TCustomScpExplorerForm::RemoteDirViewStartReading(TObject *){  Terminal->DisableThumbnails();}//---------------------------------------------------------------------------void TCustomScpExplorerForm::ChangeDirViewStyle(TOperationSide Side, TDirViewStyle DirViewStyle){  TCustomDirView * ADirView = DirView(Side);  if (ADirView->DirViewStyle != DirViewStyle)  {    if (DirViewStyle == dvsThumbnail)    {      if (dynamic_cast<TUnixDirView *>(ADirView) != NULL)      {        Configuration->Usage->Inc(L"ThumbnailsRemote");      }      else      {        Configuration->Usage->Inc(L"ThumbnailsLocal");      }    }    ADirView->DirViewStyle = DirViewStyle;    UpdateControls();  }}
 |