panel.c 134 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030
  1. /*
  2. Panel managing.
  3. Copyright (C) 1994-2018
  4. Free Software Foundation, Inc.
  5. Written by:
  6. Miguel de Icaza, 1995
  7. Timur Bakeyev, 1997, 1999
  8. Slava Zanko <slavazanko@gmail.com>, 2013
  9. Andrew Borodin <aborodin@vmail.ru>, 2013-2016
  10. This file is part of the Midnight Commander.
  11. The Midnight Commander is free software: you can redistribute it
  12. and/or modify it under the terms of the GNU General Public License as
  13. published by the Free Software Foundation, either version 3 of the License,
  14. or (at your option) any later version.
  15. The Midnight Commander is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU General Public License for more details.
  19. You should have received a copy of the GNU General Public License
  20. along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. /** \file panel.c
  23. * \brief Source: panel managin module
  24. */
  25. #include <config.h>
  26. #include <errno.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include "lib/global.h"
  31. #include "lib/tty/tty.h"
  32. #include "lib/tty/key.h" /* XCTRL and ALT macros */
  33. #include "lib/skin.h"
  34. #include "lib/strescape.h"
  35. #include "lib/mcconfig.h"
  36. #include "lib/vfs/vfs.h"
  37. #include "lib/unixcompat.h"
  38. #include "lib/search.h"
  39. #include "lib/timefmt.h" /* file_date() */
  40. #include "lib/util.h"
  41. #include "lib/widget.h"
  42. #ifdef HAVE_CHARSET
  43. #include "lib/charsets.h" /* get_codepage_id () */
  44. #endif
  45. #include "lib/event.h"
  46. #include "src/setup.h" /* For loading/saving panel options */
  47. #include "src/execute.h"
  48. #ifdef HAVE_CHARSET
  49. #include "src/selcodepage.h" /* select_charset (), SELECT_CHARSET_NO_TRANSLATE */
  50. #endif
  51. #include "src/keybind-defaults.h" /* global_keymap_t */
  52. #ifdef ENABLE_SUBSHELL
  53. #include "src/subshell/subshell.h" /* do_subshell_chdir() */
  54. #endif
  55. #include "src/usermenu.h"
  56. #include "dir.h"
  57. #include "boxes.h"
  58. #include "tree.h"
  59. #include "ext.h" /* regexp_command */
  60. #include "layout.h" /* Most layout variables are here */
  61. #include "cmd.h"
  62. #include "command.h" /* cmdline */
  63. #include "midnight.h"
  64. #include "mountlist.h" /* my_statfs */
  65. #include "panel.h"
  66. /*** global variables ****************************************************************************/
  67. /* The hook list for the select file function */
  68. hook_t *select_file_hook = NULL;
  69. /* *INDENT-OFF* */
  70. panelized_panel_t panelized_panel = { {NULL, 0, -1}, NULL };
  71. /* *INDENT-ON* */
  72. static const char *string_file_name (file_entry_t *, int);
  73. static const char *string_file_size (file_entry_t *, int);
  74. static const char *string_file_size_brief (file_entry_t *, int);
  75. static const char *string_file_type (file_entry_t *, int);
  76. static const char *string_file_mtime (file_entry_t *, int);
  77. static const char *string_file_atime (file_entry_t *, int);
  78. static const char *string_file_ctime (file_entry_t *, int);
  79. static const char *string_file_permission (file_entry_t *, int);
  80. static const char *string_file_perm_octal (file_entry_t *, int);
  81. static const char *string_file_nlinks (file_entry_t *, int);
  82. static const char *string_inode (file_entry_t *, int);
  83. static const char *string_file_nuid (file_entry_t *, int);
  84. static const char *string_file_ngid (file_entry_t *, int);
  85. static const char *string_file_owner (file_entry_t *, int);
  86. static const char *string_file_group (file_entry_t *, int);
  87. static const char *string_marked (file_entry_t *, int);
  88. static const char *string_space (file_entry_t *, int);
  89. static const char *string_dot (file_entry_t *, int);
  90. mc_fhl_t *mc_filehighlight = NULL;
  91. /*** file scope macro definitions ****************************************************************/
  92. #define NORMAL 0
  93. #define SELECTED 1
  94. #define MARKED 2
  95. #define MARKED_SELECTED 3
  96. #define STATUS 5
  97. /*** file scope type declarations ****************************************************************/
  98. typedef enum
  99. {
  100. MARK_DONT_MOVE = 0,
  101. MARK_DOWN = 1,
  102. MARK_FORCE_DOWN = 2,
  103. MARK_FORCE_UP = 3
  104. } mark_act_t;
  105. /*
  106. * This describes a format item. The parse_display_format routine parses
  107. * the user specified format and creates a linked list of format_e structures.
  108. */
  109. typedef struct format_e
  110. {
  111. struct format_e *next;
  112. int requested_field_len;
  113. int field_len;
  114. align_crt_t just_mode;
  115. gboolean expand;
  116. const char *(*string_fn) (file_entry_t *, int len);
  117. char *title;
  118. const char *id;
  119. } format_e;
  120. /* File name scroll states */
  121. typedef enum
  122. {
  123. FILENAME_NOSCROLL = 1,
  124. FILENAME_SCROLL_LEFT = 2,
  125. FILENAME_SCROLL_RIGHT = 4
  126. } filename_scroll_flag_t;
  127. /*** file scope variables ************************************************************************/
  128. /* *INDENT-OFF* */
  129. static panel_field_t panel_fields[] = {
  130. {
  131. "unsorted", 12, TRUE, J_LEFT_FIT,
  132. /* TRANSLATORS: one single character to represent 'unsorted' sort mode */
  133. /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */
  134. N_("sort|u"),
  135. N_("&Unsorted"), TRUE, FALSE,
  136. string_file_name,
  137. (GCompareFunc) unsorted
  138. }
  139. ,
  140. {
  141. "name", 12, TRUE, J_LEFT_FIT,
  142. /* TRANSLATORS: one single character to represent 'name' sort mode */
  143. /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */
  144. N_("sort|n"),
  145. N_("&Name"), TRUE, TRUE,
  146. string_file_name,
  147. (GCompareFunc) sort_name
  148. }
  149. ,
  150. {
  151. "version", 12, TRUE, J_LEFT_FIT,
  152. /* TRANSLATORS: one single character to represent 'version' sort mode */
  153. /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */
  154. N_("sort|v"),
  155. N_("&Version"), TRUE, FALSE,
  156. string_file_name,
  157. (GCompareFunc) sort_vers
  158. }
  159. ,
  160. {
  161. "extension", 12, TRUE, J_LEFT_FIT,
  162. /* TRANSLATORS: one single character to represent 'extension' sort mode */
  163. /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */
  164. N_("sort|e"),
  165. N_("E&xtension"), TRUE, FALSE,
  166. string_file_name, /* TODO: string_file_ext */
  167. (GCompareFunc) sort_ext
  168. }
  169. ,
  170. {
  171. "size", 7, FALSE, J_RIGHT,
  172. /* TRANSLATORS: one single character to represent 'size' sort mode */
  173. /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */
  174. N_("sort|s"),
  175. N_("&Size"), TRUE, TRUE,
  176. string_file_size,
  177. (GCompareFunc) sort_size
  178. }
  179. ,
  180. {
  181. "bsize", 7, FALSE, J_RIGHT,
  182. "",
  183. N_("Block Size"), FALSE, FALSE,
  184. string_file_size_brief,
  185. (GCompareFunc) sort_size
  186. }
  187. ,
  188. {
  189. "type", 1, FALSE, J_LEFT,
  190. "",
  191. "", FALSE, TRUE,
  192. string_file_type,
  193. NULL
  194. }
  195. ,
  196. {
  197. "mtime", 12, FALSE, J_RIGHT,
  198. /* TRANSLATORS: one single character to represent 'Modify time' sort mode */
  199. /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */
  200. N_("sort|m"),
  201. N_("&Modify time"), TRUE, TRUE,
  202. string_file_mtime,
  203. (GCompareFunc) sort_time
  204. }
  205. ,
  206. {
  207. "atime", 12, FALSE, J_RIGHT,
  208. /* TRANSLATORS: one single character to represent 'Access time' sort mode */
  209. /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */
  210. N_("sort|a"),
  211. N_("&Access time"), TRUE, TRUE,
  212. string_file_atime,
  213. (GCompareFunc) sort_atime
  214. }
  215. ,
  216. {
  217. "ctime", 12, FALSE, J_RIGHT,
  218. /* TRANSLATORS: one single character to represent 'Change time' sort mode */
  219. /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */
  220. N_("sort|h"),
  221. N_("C&hange time"), TRUE, TRUE,
  222. string_file_ctime,
  223. (GCompareFunc) sort_ctime
  224. }
  225. ,
  226. {
  227. "perm", 10, FALSE, J_LEFT,
  228. "",
  229. N_("Permission"), FALSE, TRUE,
  230. string_file_permission,
  231. NULL
  232. }
  233. ,
  234. {
  235. "mode", 6, FALSE, J_RIGHT,
  236. "",
  237. N_("Perm"), FALSE, TRUE,
  238. string_file_perm_octal,
  239. NULL
  240. }
  241. ,
  242. {
  243. "nlink", 2, FALSE, J_RIGHT,
  244. "",
  245. N_("Nl"), FALSE, TRUE,
  246. string_file_nlinks, NULL
  247. }
  248. ,
  249. {
  250. "inode", 5, FALSE, J_RIGHT,
  251. /* TRANSLATORS: one single character to represent 'inode' sort mode */
  252. /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */
  253. N_("sort|i"),
  254. N_("&Inode"), TRUE, TRUE,
  255. string_inode,
  256. (GCompareFunc) sort_inode
  257. }
  258. ,
  259. {
  260. "nuid", 5, FALSE, J_RIGHT,
  261. "",
  262. N_("UID"), FALSE, FALSE,
  263. string_file_nuid,
  264. NULL
  265. }
  266. ,
  267. {
  268. "ngid", 5, FALSE, J_RIGHT,
  269. "",
  270. N_("GID"), FALSE, FALSE,
  271. string_file_ngid,
  272. NULL
  273. }
  274. ,
  275. {
  276. "owner", 8, FALSE, J_LEFT_FIT,
  277. "",
  278. N_("Owner"), FALSE, TRUE,
  279. string_file_owner,
  280. NULL
  281. }
  282. ,
  283. {
  284. "group", 8, FALSE, J_LEFT_FIT,
  285. "",
  286. N_("Group"), FALSE, TRUE,
  287. string_file_group,
  288. NULL
  289. }
  290. ,
  291. {
  292. "mark", 1, FALSE, J_RIGHT,
  293. "",
  294. " ", FALSE, TRUE,
  295. string_marked,
  296. NULL
  297. }
  298. ,
  299. {
  300. "|", 1, FALSE, J_RIGHT,
  301. "",
  302. " ", FALSE, TRUE,
  303. NULL,
  304. NULL
  305. }
  306. ,
  307. {
  308. "space", 1, FALSE, J_RIGHT,
  309. "",
  310. " ", FALSE, TRUE,
  311. string_space,
  312. NULL
  313. }
  314. ,
  315. {
  316. "dot", 1, FALSE, J_RIGHT,
  317. "",
  318. " ", FALSE, FALSE,
  319. string_dot,
  320. NULL
  321. }
  322. ,
  323. {
  324. NULL, 0, FALSE, J_RIGHT, NULL, NULL, FALSE, FALSE, NULL, NULL
  325. }
  326. };
  327. /* *INDENT-ON* */
  328. static char *panel_sort_up_sign = NULL;
  329. static char *panel_sort_down_sign = NULL;
  330. static char *panel_hiddenfiles_sign_show = NULL;
  331. static char *panel_hiddenfiles_sign_hide = NULL;
  332. static char *panel_history_prev_item_sign = NULL;
  333. static char *panel_history_next_item_sign = NULL;
  334. static char *panel_history_show_list_sign = NULL;
  335. static char *panel_filename_scroll_left_char = NULL;
  336. static char *panel_filename_scroll_right_char = NULL;
  337. /* Panel that selection started */
  338. static WPanel *mouse_mark_panel = NULL;
  339. static int mouse_marking = 0;
  340. static int state_mark = 0;
  341. /* --------------------------------------------------------------------------------------------- */
  342. /*** file scope functions ************************************************************************/
  343. /* --------------------------------------------------------------------------------------------- */
  344. static void
  345. set_colors (const WPanel * panel)
  346. {
  347. (void) panel;
  348. tty_set_normal_attrs ();
  349. tty_setcolor (NORMAL_COLOR);
  350. }
  351. /* --------------------------------------------------------------------------------------------- */
  352. /** Delete format string, it is a linked list */
  353. static void
  354. delete_format (format_e * format)
  355. {
  356. while (format != NULL)
  357. {
  358. format_e *next = format->next;
  359. g_free (format->title);
  360. g_free (format);
  361. format = next;
  362. }
  363. }
  364. /* --------------------------------------------------------------------------------------------- */
  365. /** Extract the number of available lines in a panel */
  366. static int
  367. panel_lines (const WPanel * p)
  368. {
  369. /* 3 lines are: top frame, column header, botton frame */
  370. return (CONST_WIDGET (p)->lines - 3 - (panels_options.show_mini_info ? 2 : 0));
  371. }
  372. /* --------------------------------------------------------------------------------------------- */
  373. /** This code relies on the default justification!!! */
  374. static void
  375. add_permission_string (const char *dest, int width, file_entry_t * fe, int attr, int color,
  376. gboolean is_octal)
  377. {
  378. int i, r, l;
  379. l = get_user_permissions (&fe->st);
  380. if (is_octal)
  381. {
  382. /* Place of the access bit in octal mode */
  383. l = width + l - 3;
  384. r = l + 1;
  385. }
  386. else
  387. {
  388. /* The same to the triplet in string mode */
  389. l = l * 3 + 1;
  390. r = l + 3;
  391. }
  392. for (i = 0; i < width; i++)
  393. {
  394. if (i >= l && i < r)
  395. {
  396. if (attr == SELECTED || attr == MARKED_SELECTED)
  397. tty_setcolor (MARKED_SELECTED_COLOR);
  398. else
  399. tty_setcolor (MARKED_COLOR);
  400. }
  401. else if (color >= 0)
  402. tty_setcolor (color);
  403. else
  404. tty_lowlevel_setcolor (-color);
  405. tty_print_char (dest[i]);
  406. }
  407. }
  408. /* --------------------------------------------------------------------------------------------- */
  409. /** String representations of various file attributes name */
  410. static const char *
  411. string_file_name (file_entry_t * fe, int len)
  412. {
  413. static char buffer[MC_MAXPATHLEN * MB_LEN_MAX + 1];
  414. (void) len;
  415. g_strlcpy (buffer, fe->fname, sizeof (buffer));
  416. return buffer;
  417. }
  418. /* --------------------------------------------------------------------------------------------- */
  419. static unsigned int
  420. ilog10 (dev_t n)
  421. {
  422. unsigned int digits = 0;
  423. do
  424. {
  425. digits++;
  426. n /= 10;
  427. }
  428. while (n != 0);
  429. return digits;
  430. }
  431. /* --------------------------------------------------------------------------------------------- */
  432. static void
  433. format_device_number (char *buf, size_t bufsize, dev_t dev)
  434. {
  435. dev_t major_dev = major (dev);
  436. dev_t minor_dev = minor (dev);
  437. unsigned int major_digits = ilog10 (major_dev);
  438. unsigned int minor_digits = ilog10 (minor_dev);
  439. g_assert (bufsize >= 1);
  440. if (major_digits + 1 + minor_digits + 1 <= bufsize)
  441. g_snprintf (buf, bufsize, "%lu,%lu", (unsigned long) major_dev, (unsigned long) minor_dev);
  442. else
  443. g_strlcpy (buf, _("[dev]"), bufsize);
  444. }
  445. /* --------------------------------------------------------------------------------------------- */
  446. /** size */
  447. static const char *
  448. string_file_size (file_entry_t * fe, int len)
  449. {
  450. static char buffer[BUF_TINY];
  451. /* Don't ever show size of ".." since we don't calculate it */
  452. if (DIR_IS_DOTDOT (fe->fname))
  453. return _("UP--DIR");
  454. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  455. if (S_ISBLK (fe->st.st_mode) || S_ISCHR (fe->st.st_mode))
  456. format_device_number (buffer, len + 1, fe->st.st_rdev);
  457. else
  458. #endif
  459. size_trunc_len (buffer, (unsigned int) len, fe->st.st_size, 0, panels_options.kilobyte_si);
  460. return buffer;
  461. }
  462. /* --------------------------------------------------------------------------------------------- */
  463. /** bsize */
  464. static const char *
  465. string_file_size_brief (file_entry_t * fe, int len)
  466. {
  467. if (S_ISLNK (fe->st.st_mode) && !link_isdir (fe))
  468. return _("SYMLINK");
  469. if ((S_ISDIR (fe->st.st_mode) || link_isdir (fe)) && !DIR_IS_DOTDOT (fe->fname))
  470. return _("SUB-DIR");
  471. return string_file_size (fe, len);
  472. }
  473. /* --------------------------------------------------------------------------------------------- */
  474. /** This functions return a string representation of a file entry type */
  475. static const char *
  476. string_file_type (file_entry_t * fe, int len)
  477. {
  478. static char buffer[2];
  479. (void) len;
  480. if (S_ISDIR (fe->st.st_mode))
  481. buffer[0] = PATH_SEP;
  482. else if (S_ISLNK (fe->st.st_mode))
  483. {
  484. if (link_isdir (fe))
  485. buffer[0] = '~';
  486. else if (fe->f.stale_link)
  487. buffer[0] = '!';
  488. else
  489. buffer[0] = '@';
  490. }
  491. else if (S_ISCHR (fe->st.st_mode))
  492. buffer[0] = '-';
  493. else if (S_ISSOCK (fe->st.st_mode))
  494. buffer[0] = '=';
  495. else if (S_ISDOOR (fe->st.st_mode))
  496. buffer[0] = '>';
  497. else if (S_ISBLK (fe->st.st_mode))
  498. buffer[0] = '+';
  499. else if (S_ISFIFO (fe->st.st_mode))
  500. buffer[0] = '|';
  501. else if (S_ISNAM (fe->st.st_mode))
  502. buffer[0] = '#';
  503. else if (!S_ISREG (fe->st.st_mode))
  504. buffer[0] = '?'; /* non-regular of unknown kind */
  505. else if (is_exe (fe->st.st_mode))
  506. buffer[0] = '*';
  507. else
  508. buffer[0] = ' ';
  509. buffer[1] = '\0';
  510. return buffer;
  511. }
  512. /* --------------------------------------------------------------------------------------------- */
  513. /** mtime */
  514. static const char *
  515. string_file_mtime (file_entry_t * fe, int len)
  516. {
  517. (void) len;
  518. return file_date (fe->st.st_mtime);
  519. }
  520. /* --------------------------------------------------------------------------------------------- */
  521. /** atime */
  522. static const char *
  523. string_file_atime (file_entry_t * fe, int len)
  524. {
  525. (void) len;
  526. return file_date (fe->st.st_atime);
  527. }
  528. /* --------------------------------------------------------------------------------------------- */
  529. /** ctime */
  530. static const char *
  531. string_file_ctime (file_entry_t * fe, int len)
  532. {
  533. (void) len;
  534. return file_date (fe->st.st_ctime);
  535. }
  536. /* --------------------------------------------------------------------------------------------- */
  537. /** perm */
  538. static const char *
  539. string_file_permission (file_entry_t * fe, int len)
  540. {
  541. (void) len;
  542. return string_perm (fe->st.st_mode);
  543. }
  544. /* --------------------------------------------------------------------------------------------- */
  545. /** mode */
  546. static const char *
  547. string_file_perm_octal (file_entry_t * fe, int len)
  548. {
  549. static char buffer[10];
  550. (void) len;
  551. g_snprintf (buffer, sizeof (buffer), "0%06lo", (unsigned long) fe->st.st_mode);
  552. return buffer;
  553. }
  554. /* --------------------------------------------------------------------------------------------- */
  555. /** nlink */
  556. static const char *
  557. string_file_nlinks (file_entry_t * fe, int len)
  558. {
  559. static char buffer[BUF_TINY];
  560. (void) len;
  561. g_snprintf (buffer, sizeof (buffer), "%16d", (int) fe->st.st_nlink);
  562. return buffer;
  563. }
  564. /* --------------------------------------------------------------------------------------------- */
  565. /** inode */
  566. static const char *
  567. string_inode (file_entry_t * fe, int len)
  568. {
  569. static char buffer[10];
  570. (void) len;
  571. g_snprintf (buffer, sizeof (buffer), "%lu", (unsigned long) fe->st.st_ino);
  572. return buffer;
  573. }
  574. /* --------------------------------------------------------------------------------------------- */
  575. /** nuid */
  576. static const char *
  577. string_file_nuid (file_entry_t * fe, int len)
  578. {
  579. static char buffer[10];
  580. (void) len;
  581. g_snprintf (buffer, sizeof (buffer), "%lu", (unsigned long) fe->st.st_uid);
  582. return buffer;
  583. }
  584. /* --------------------------------------------------------------------------------------------- */
  585. /** ngid */
  586. static const char *
  587. string_file_ngid (file_entry_t * fe, int len)
  588. {
  589. static char buffer[10];
  590. (void) len;
  591. g_snprintf (buffer, sizeof (buffer), "%lu", (unsigned long) fe->st.st_gid);
  592. return buffer;
  593. }
  594. /* --------------------------------------------------------------------------------------------- */
  595. /** owner */
  596. static const char *
  597. string_file_owner (file_entry_t * fe, int len)
  598. {
  599. (void) len;
  600. return get_owner (fe->st.st_uid);
  601. }
  602. /* --------------------------------------------------------------------------------------------- */
  603. /** group */
  604. static const char *
  605. string_file_group (file_entry_t * fe, int len)
  606. {
  607. (void) len;
  608. return get_group (fe->st.st_gid);
  609. }
  610. /* --------------------------------------------------------------------------------------------- */
  611. /** mark */
  612. static const char *
  613. string_marked (file_entry_t * fe, int len)
  614. {
  615. (void) len;
  616. return fe->f.marked ? "*" : " ";
  617. }
  618. /* --------------------------------------------------------------------------------------------- */
  619. /** space */
  620. static const char *
  621. string_space (file_entry_t * fe, int len)
  622. {
  623. (void) fe;
  624. (void) len;
  625. return " ";
  626. }
  627. /* --------------------------------------------------------------------------------------------- */
  628. /** dot */
  629. static const char *
  630. string_dot (file_entry_t * fe, int len)
  631. {
  632. (void) fe;
  633. (void) len;
  634. return ".";
  635. }
  636. /* --------------------------------------------------------------------------------------------- */
  637. static int
  638. file_compute_color (int attr, file_entry_t * fe)
  639. {
  640. switch (attr)
  641. {
  642. case SELECTED:
  643. return (SELECTED_COLOR);
  644. case MARKED:
  645. return (MARKED_COLOR);
  646. case MARKED_SELECTED:
  647. return (MARKED_SELECTED_COLOR);
  648. case STATUS:
  649. return (NORMAL_COLOR);
  650. case NORMAL:
  651. default:
  652. if (!panels_options.filetype_mode)
  653. return (NORMAL_COLOR);
  654. }
  655. return mc_fhl_get_color (mc_filehighlight, fe);
  656. }
  657. /* --------------------------------------------------------------------------------------------- */
  658. /** Returns the number of items in the given panel */
  659. static int
  660. panel_items (const WPanel * p)
  661. {
  662. return panel_lines (p) * p->list_cols;
  663. }
  664. /* --------------------------------------------------------------------------------------------- */
  665. /** Formats the file number file_index of panel in the buffer dest */
  666. static filename_scroll_flag_t
  667. format_file (WPanel * panel, int file_index, int width, int attr, gboolean isstatus,
  668. int *field_length)
  669. {
  670. int color = NORMAL_COLOR;
  671. int length = 0;
  672. format_e *format, *home;
  673. file_entry_t *fe = NULL;
  674. filename_scroll_flag_t res = FILENAME_NOSCROLL;
  675. *field_length = 0;
  676. if (file_index < panel->dir.len)
  677. {
  678. fe = &panel->dir.list[file_index];
  679. color = file_compute_color (attr, fe);
  680. }
  681. home = isstatus ? panel->status_format : panel->format;
  682. for (format = home; format != NULL && length != width; format = format->next)
  683. {
  684. if (format->string_fn != NULL)
  685. {
  686. const char *txt = " ";
  687. int len, perm = 0;
  688. const char *prepared_text;
  689. int name_offset = 0;
  690. if (fe != NULL)
  691. txt = format->string_fn (fe, format->field_len);
  692. len = format->field_len;
  693. if (len + length > width)
  694. len = width - length;
  695. if (len <= 0)
  696. break;
  697. if (!isstatus && panel->content_shift > -1 && strcmp (format->id, "name") == 0)
  698. {
  699. int str_len;
  700. int i;
  701. *field_length = len + 1;
  702. str_len = str_length (txt);
  703. i = MAX (0, str_len - len);
  704. panel->max_shift = MAX (panel->max_shift, i);
  705. i = MIN (panel->content_shift, i);
  706. if (i > -1)
  707. {
  708. name_offset = str_offset_to_pos (txt, i);
  709. if (str_len > len)
  710. {
  711. res = FILENAME_SCROLL_LEFT;
  712. if (str_length (txt + name_offset) > len)
  713. res |= FILENAME_SCROLL_RIGHT;
  714. }
  715. }
  716. }
  717. if (panels_options.permission_mode)
  718. {
  719. if (strcmp (format->id, "perm") == 0)
  720. perm = 1;
  721. else if (strcmp (format->id, "mode") == 0)
  722. perm = 2;
  723. }
  724. if (color >= 0)
  725. tty_setcolor (color);
  726. else
  727. tty_lowlevel_setcolor (-color);
  728. if (!isstatus && panel->content_shift > -1)
  729. prepared_text =
  730. str_fit_to_term (txt + name_offset, len, HIDE_FIT (format->just_mode));
  731. else
  732. prepared_text = str_fit_to_term (txt, len, format->just_mode);
  733. if (perm != 0 && fe != NULL)
  734. add_permission_string (prepared_text, format->field_len, fe, attr, color,
  735. perm != 1);
  736. else
  737. tty_print_string (prepared_text);
  738. length += len;
  739. }
  740. else
  741. {
  742. if (attr == SELECTED || attr == MARKED_SELECTED)
  743. tty_setcolor (SELECTED_COLOR);
  744. else
  745. tty_setcolor (NORMAL_COLOR);
  746. tty_print_one_vline (TRUE);
  747. length++;
  748. }
  749. }
  750. if (length < width)
  751. {
  752. int y, x;
  753. tty_getyx (&y, &x);
  754. tty_draw_hline (y, x, ' ', width - length);
  755. }
  756. return res;
  757. }
  758. /* --------------------------------------------------------------------------------------------- */
  759. static void
  760. repaint_file (WPanel * panel, int file_index, gboolean mv, int attr, gboolean isstatus)
  761. {
  762. Widget *w = WIDGET (panel);
  763. int nth_column = 0;
  764. int width;
  765. int offset = 0;
  766. filename_scroll_flag_t ret_frm;
  767. int ypos = 0;
  768. gboolean panel_is_split;
  769. int fln = 0;
  770. panel_is_split = !isstatus && panel->list_cols > 1;
  771. width = w->cols - 2;
  772. if (panel_is_split)
  773. {
  774. nth_column = (file_index - panel->top_file) / panel_lines (panel);
  775. width /= panel->list_cols;
  776. offset = width * nth_column;
  777. if (nth_column + 1 >= panel->list_cols)
  778. width = w->cols - offset - 2;
  779. }
  780. /* Nothing to paint */
  781. if (width <= 0)
  782. return;
  783. if (mv)
  784. {
  785. ypos = file_index - panel->top_file;
  786. if (panel_is_split)
  787. ypos %= panel_lines (panel);
  788. ypos += 2; /* top frame and header */
  789. widget_move (w, ypos, offset + 1);
  790. }
  791. ret_frm = format_file (panel, file_index, width, attr, isstatus, &fln);
  792. if (panel_is_split && nth_column + 1 < panel->list_cols)
  793. {
  794. tty_setcolor (NORMAL_COLOR);
  795. tty_print_one_vline (TRUE);
  796. }
  797. if (ret_frm != FILENAME_NOSCROLL && mv)
  798. {
  799. if (!panel_is_split && fln > 0)
  800. {
  801. if (panel->list_format != list_long)
  802. width = fln;
  803. else
  804. {
  805. offset = width - fln + 1;
  806. width = fln - 1;
  807. }
  808. }
  809. widget_move (w, ypos, offset);
  810. tty_setcolor (NORMAL_COLOR);
  811. tty_print_string (panel_filename_scroll_left_char);
  812. if ((ret_frm & FILENAME_SCROLL_RIGHT) != 0)
  813. {
  814. offset += width;
  815. if (nth_column + 1 >= panel->list_cols)
  816. offset++;
  817. widget_move (w, ypos, offset);
  818. tty_setcolor (NORMAL_COLOR);
  819. tty_print_string (panel_filename_scroll_right_char);
  820. }
  821. }
  822. }
  823. /* --------------------------------------------------------------------------------------------- */
  824. static void
  825. display_mini_info (WPanel * panel)
  826. {
  827. Widget *w = WIDGET (panel);
  828. if (!panels_options.show_mini_info)
  829. return;
  830. widget_move (w, panel_lines (panel) + 3, 1);
  831. if (panel->searching)
  832. {
  833. tty_setcolor (INPUT_COLOR);
  834. tty_print_char ('/');
  835. tty_print_string (str_fit_to_term (panel->search_buffer, w->cols - 3, J_LEFT));
  836. return;
  837. }
  838. /* Status resolves links and show them */
  839. set_colors (panel);
  840. if (S_ISLNK (panel->dir.list[panel->selected].st.st_mode))
  841. {
  842. char link_target[MC_MAXPATHLEN];
  843. vfs_path_t *lc_link_vpath;
  844. int len;
  845. lc_link_vpath =
  846. vfs_path_append_new (panel->cwd_vpath, panel->dir.list[panel->selected].fname,
  847. (char *) NULL);
  848. len = mc_readlink (lc_link_vpath, link_target, MC_MAXPATHLEN - 1);
  849. vfs_path_free (lc_link_vpath);
  850. if (len > 0)
  851. {
  852. link_target[len] = 0;
  853. tty_print_string ("-> ");
  854. tty_print_string (str_fit_to_term (link_target, w->cols - 5, J_LEFT_FIT));
  855. }
  856. else
  857. tty_print_string (str_fit_to_term (_("<readlink failed>"), w->cols - 2, J_LEFT));
  858. }
  859. else if (DIR_IS_DOTDOT (panel->dir.list[panel->selected].fname))
  860. {
  861. /* FIXME:
  862. * while loading directory (dir_list_load() and dir_list_reload()),
  863. * the actual stat info about ".." directory isn't got;
  864. * so just don't display incorrect info about ".." directory */
  865. tty_print_string (str_fit_to_term (_("UP--DIR"), w->cols - 2, J_LEFT));
  866. }
  867. else
  868. /* Default behavior */
  869. repaint_file (panel, panel->selected, FALSE, STATUS, TRUE);
  870. }
  871. /* --------------------------------------------------------------------------------------------- */
  872. static void
  873. paint_dir (WPanel * panel)
  874. {
  875. int i;
  876. int items; /* Number of items */
  877. items = panel_items (panel);
  878. /* reset max len of filename because we have the new max length for the new file list */
  879. panel->max_shift = -1;
  880. for (i = 0; i < items; i++)
  881. {
  882. int color = 0; /* Color value of the line */
  883. if (i + panel->top_file < panel->dir.len)
  884. {
  885. color = 2 * (panel->dir.list[i + panel->top_file].f.marked);
  886. color += (panel->selected == i + panel->top_file && panel->active);
  887. }
  888. repaint_file (panel, i + panel->top_file, TRUE, color, FALSE);
  889. }
  890. tty_set_normal_attrs ();
  891. }
  892. /* --------------------------------------------------------------------------------------------- */
  893. static void
  894. display_total_marked_size (const WPanel * panel, int y, int x, gboolean size_only)
  895. {
  896. const Widget *w = CONST_WIDGET (panel);
  897. char buffer[BUF_SMALL], b_bytes[BUF_SMALL];
  898. const char *buf;
  899. int cols;
  900. if (panel->marked <= 0)
  901. return;
  902. buf = size_only ? b_bytes : buffer;
  903. cols = w->cols - 2;
  904. g_strlcpy (b_bytes, size_trunc_sep (panel->total, panels_options.kilobyte_si),
  905. sizeof (b_bytes));
  906. if (!size_only)
  907. g_snprintf (buffer, sizeof (buffer),
  908. ngettext ("%s in %d file", "%s in %d files", panel->marked),
  909. b_bytes, panel->marked);
  910. /* don't forget spaces around buffer content */
  911. buf = str_trunc (buf, cols - 4);
  912. if (x < 0)
  913. /* center in panel */
  914. x = (w->cols - str_term_width1 (buf)) / 2 - 1;
  915. /*
  916. * y == panel_lines (panel) + 2 for mini_info_separator
  917. * y == w->lines - 1 for panel bottom frame
  918. */
  919. widget_move (w, y, x);
  920. tty_setcolor (MARKED_COLOR);
  921. tty_printf (" %s ", buf);
  922. }
  923. /* --------------------------------------------------------------------------------------------- */
  924. static void
  925. mini_info_separator (const WPanel * panel)
  926. {
  927. if (panels_options.show_mini_info)
  928. {
  929. const Widget *w = CONST_WIDGET (panel);
  930. int y;
  931. y = panel_lines (panel) + 2;
  932. tty_setcolor (NORMAL_COLOR);
  933. tty_draw_hline (w->y + y, w->x + 1, ACS_HLINE, w->cols - 2);
  934. /* Status displays total marked size.
  935. * Centered in panel, full format. */
  936. display_total_marked_size (panel, y, -1, FALSE);
  937. }
  938. }
  939. /* --------------------------------------------------------------------------------------------- */
  940. static void
  941. show_free_space (const WPanel * panel)
  942. {
  943. /* Used to figure out how many free space we have */
  944. static struct my_statfs myfs_stats;
  945. /* Old current working directory for displaying free space */
  946. static char *old_cwd = NULL;
  947. /* Don't try to stat non-local fs */
  948. if (!vfs_file_is_local (panel->cwd_vpath) || !free_space)
  949. return;
  950. if (old_cwd == NULL || strcmp (old_cwd, vfs_path_as_str (panel->cwd_vpath)) != 0)
  951. {
  952. char rpath[PATH_MAX];
  953. init_my_statfs ();
  954. g_free (old_cwd);
  955. old_cwd = g_strdup (vfs_path_as_str (panel->cwd_vpath));
  956. if (mc_realpath (old_cwd, rpath) == NULL)
  957. return;
  958. my_statfs (&myfs_stats, rpath);
  959. }
  960. if (myfs_stats.avail != 0 || myfs_stats.total != 0)
  961. {
  962. const Widget *w = CONST_WIDGET (panel);
  963. char buffer1[6], buffer2[6], tmp[BUF_SMALL];
  964. size_trunc_len (buffer1, sizeof (buffer1) - 1, myfs_stats.avail, 1,
  965. panels_options.kilobyte_si);
  966. size_trunc_len (buffer2, sizeof (buffer2) - 1, myfs_stats.total, 1,
  967. panels_options.kilobyte_si);
  968. g_snprintf (tmp, sizeof (tmp), " %s/%s (%d%%) ", buffer1, buffer2,
  969. myfs_stats.total == 0 ? 0 :
  970. (int) (100 * (long double) myfs_stats.avail / myfs_stats.total));
  971. widget_move (w, w->lines - 1, w->cols - 2 - (int) strlen (tmp));
  972. tty_setcolor (NORMAL_COLOR);
  973. tty_print_string (tmp);
  974. }
  975. }
  976. /* --------------------------------------------------------------------------------------------- */
  977. /**
  978. * Prepare path string for showing in panel's header.
  979. * Passwords will removed, also home dir will replaced by ~
  980. *
  981. * @param panel WPanel object
  982. *
  983. * @return newly allocated string.
  984. */
  985. static char *
  986. panel_correct_path_to_show (const WPanel * panel)
  987. {
  988. vfs_path_t *last_vpath;
  989. const vfs_path_element_t *path_element;
  990. char *return_path;
  991. int elements_count;
  992. elements_count = vfs_path_elements_count (panel->cwd_vpath);
  993. /* get last path element */
  994. path_element = vfs_path_element_clone (vfs_path_get_by_index (panel->cwd_vpath, -1));
  995. if (elements_count > 1 && (strcmp (path_element->class->name, "cpiofs") == 0 ||
  996. strcmp (path_element->class->name, "extfs") == 0 ||
  997. strcmp (path_element->class->name, "tarfs") == 0))
  998. {
  999. const char *archive_name;
  1000. const vfs_path_element_t *prev_path_element;
  1001. /* get previous path element for catching archive name */
  1002. prev_path_element = vfs_path_get_by_index (panel->cwd_vpath, -2);
  1003. archive_name = strrchr (prev_path_element->path, PATH_SEP);
  1004. if (archive_name != NULL)
  1005. last_vpath = vfs_path_from_str_flags (archive_name + 1, VPF_NO_CANON);
  1006. else
  1007. {
  1008. last_vpath = vfs_path_from_str_flags (prev_path_element->path, VPF_NO_CANON);
  1009. last_vpath->relative = TRUE;
  1010. }
  1011. }
  1012. else
  1013. {
  1014. last_vpath = vfs_path_new ();
  1015. last_vpath->relative = TRUE;
  1016. }
  1017. vfs_path_add_element (last_vpath, path_element);
  1018. return_path =
  1019. vfs_path_to_str_flags (last_vpath, 0,
  1020. VPF_STRIP_HOME | VPF_STRIP_PASSWORD | VPF_HIDE_CHARSET);
  1021. vfs_path_free (last_vpath);
  1022. return return_path;
  1023. }
  1024. /* --------------------------------------------------------------------------------------------- */
  1025. /**
  1026. * Get Current path element encoding
  1027. *
  1028. * @param panel WPanel object
  1029. *
  1030. * @return newly allocated string or NULL if path charset is same as system charset
  1031. */
  1032. #ifdef HAVE_CHARSET
  1033. static char *
  1034. panel_get_encoding_info_str (const WPanel * panel)
  1035. {
  1036. char *ret_str = NULL;
  1037. const vfs_path_element_t *path_element;
  1038. path_element = vfs_path_get_by_index (panel->cwd_vpath, -1);
  1039. if (path_element->encoding != NULL)
  1040. ret_str = g_strdup_printf ("[%s]", path_element->encoding);
  1041. return ret_str;
  1042. }
  1043. #endif
  1044. /* --------------------------------------------------------------------------------------------- */
  1045. static void
  1046. show_dir (const WPanel * panel)
  1047. {
  1048. const Widget *w = CONST_WIDGET (panel);
  1049. gchar *tmp;
  1050. set_colors (panel);
  1051. tty_draw_box (w->y, w->x, w->lines, w->cols, FALSE);
  1052. if (panels_options.show_mini_info)
  1053. {
  1054. int y;
  1055. y = panel_lines (panel) + 2;
  1056. widget_move (w, y, 0);
  1057. tty_print_alt_char (ACS_LTEE, FALSE);
  1058. widget_move (w, y, w->cols - 1);
  1059. tty_print_alt_char (ACS_RTEE, FALSE);
  1060. }
  1061. widget_move (w, 0, 1);
  1062. tty_print_string (panel_history_prev_item_sign);
  1063. tmp = panels_options.show_dot_files ? panel_hiddenfiles_sign_show : panel_hiddenfiles_sign_hide;
  1064. tmp = g_strdup_printf ("%s[%s]%s", tmp, panel_history_show_list_sign,
  1065. panel_history_next_item_sign);
  1066. widget_move (w, 0, w->cols - 6);
  1067. tty_print_string (tmp);
  1068. g_free (tmp);
  1069. widget_move (w, 0, 3);
  1070. if (panel->is_panelized)
  1071. tty_printf (" %s ", _("Panelize"));
  1072. #ifdef HAVE_CHARSET
  1073. else
  1074. {
  1075. tmp = panel_get_encoding_info_str (panel);
  1076. if (tmp != NULL)
  1077. {
  1078. tty_printf ("%s", tmp);
  1079. widget_move (w, 0, 3 + strlen (tmp));
  1080. g_free (tmp);
  1081. }
  1082. }
  1083. #endif
  1084. if (panel->active)
  1085. tty_setcolor (REVERSE_COLOR);
  1086. tmp = panel_correct_path_to_show (panel);
  1087. tty_printf (" %s ", str_term_trim (tmp, MIN (MAX (w->cols - 12, 0), w->cols)));
  1088. g_free (tmp);
  1089. if (!panels_options.show_mini_info)
  1090. {
  1091. if (panel->marked == 0)
  1092. {
  1093. /* Show size of curret file in the bottom of panel */
  1094. if (S_ISREG (panel->dir.list[panel->selected].st.st_mode))
  1095. {
  1096. char buffer[BUF_SMALL];
  1097. g_snprintf (buffer, sizeof (buffer), " %s ",
  1098. size_trunc_sep (panel->dir.list[panel->selected].st.st_size,
  1099. panels_options.kilobyte_si));
  1100. tty_setcolor (NORMAL_COLOR);
  1101. widget_move (w, w->lines - 1, 4);
  1102. tty_print_string (buffer);
  1103. }
  1104. }
  1105. else
  1106. {
  1107. /* Show total size of marked files
  1108. * In the bottom of panel, display size only. */
  1109. display_total_marked_size (panel, w->lines - 1, 2, TRUE);
  1110. }
  1111. }
  1112. show_free_space (panel);
  1113. if (panel->active)
  1114. tty_set_normal_attrs ();
  1115. }
  1116. /* --------------------------------------------------------------------------------------------- */
  1117. static void
  1118. adjust_top_file (WPanel * panel)
  1119. {
  1120. int items;
  1121. /* Update panel->selected to avoid out of range in panel->dir.list[panel->selected]
  1122. * when panel is redrawing when directory is reloading, for example in path:
  1123. * dir_list_reload() -> mc_refresh() -> dialog_change_screen_size() ->
  1124. * midnight_callback (MSG_RESIZE) -> setup_panels() -> panel_callback(MSG_DRAW) ->
  1125. * display_mini_info()
  1126. */
  1127. panel->selected = CLAMP (panel->selected, 0, panel->dir.len - 1);
  1128. items = panel_items (panel);
  1129. if (panel->dir.len <= items)
  1130. {
  1131. /* If all files fit, show them all. */
  1132. panel->top_file = 0;
  1133. }
  1134. else
  1135. {
  1136. int i;
  1137. /* top_file has to be in the range [selected-items+1, selected] so that
  1138. the selected file is visible.
  1139. top_file should be in the range [0, count-items] so that there's
  1140. no empty space wasted.
  1141. Within these ranges, adjust it by as little as possible. */
  1142. if (panel->top_file < 0)
  1143. panel->top_file = 0;
  1144. i = panel->selected - items + 1;
  1145. if (panel->top_file < i)
  1146. panel->top_file = i;
  1147. i = panel->dir.len - items;
  1148. if (panel->top_file > i)
  1149. panel->top_file = i;
  1150. if (panel->top_file > panel->selected)
  1151. panel->top_file = panel->selected;
  1152. }
  1153. }
  1154. /* --------------------------------------------------------------------------------------------- */
  1155. /** add "#enc:encodning" to end of path */
  1156. /* if path end width a previous #enc:, only encoding is changed no additional
  1157. * #enc: is appended
  1158. * retun new string
  1159. */
  1160. static char *
  1161. panel_save_name (WPanel * panel)
  1162. {
  1163. /* If the program is shuting down */
  1164. if ((mc_global.midnight_shutdown && auto_save_setup) || saving_setup)
  1165. return g_strdup (panel->panel_name);
  1166. return g_strconcat ("Temporal:", panel->panel_name, (char *) NULL);
  1167. }
  1168. /* --------------------------------------------------------------------------------------------- */
  1169. static void
  1170. directory_history_add (WPanel * panel, const vfs_path_t * vpath)
  1171. {
  1172. char *tmp;
  1173. tmp = vfs_path_to_str_flags (vpath, 0, VPF_STRIP_PASSWORD);
  1174. panel->dir_history = list_append_unique (panel->dir_history, tmp);
  1175. panel->dir_history_current = panel->dir_history;
  1176. }
  1177. /* --------------------------------------------------------------------------------------------- */
  1178. /* "history_load" event handler */
  1179. static gboolean
  1180. panel_load_history (const gchar * event_group_name, const gchar * event_name,
  1181. gpointer init_data, gpointer data)
  1182. {
  1183. WPanel *p = PANEL (init_data);
  1184. ev_history_load_save_t *ev = (ev_history_load_save_t *) data;
  1185. (void) event_group_name;
  1186. (void) event_name;
  1187. if (ev->receiver == NULL || ev->receiver == WIDGET (p))
  1188. {
  1189. if (ev->cfg != NULL)
  1190. p->dir_history = history_load (ev->cfg, p->hist_name);
  1191. else
  1192. p->dir_history = history_get (p->hist_name);
  1193. directory_history_add (p, p->cwd_vpath);
  1194. }
  1195. return TRUE;
  1196. }
  1197. /* --------------------------------------------------------------------------------------------- */
  1198. /* "history_save" event handler */
  1199. static gboolean
  1200. panel_save_history (const gchar * event_group_name, const gchar * event_name,
  1201. gpointer init_data, gpointer data)
  1202. {
  1203. WPanel *p = PANEL (init_data);
  1204. (void) event_group_name;
  1205. (void) event_name;
  1206. if (p->dir_history != NULL)
  1207. {
  1208. ev_history_load_save_t *ev = (ev_history_load_save_t *) data;
  1209. history_save (ev->cfg, p->hist_name, p->dir_history);
  1210. }
  1211. return TRUE;
  1212. }
  1213. /* --------------------------------------------------------------------------------------------- */
  1214. static void
  1215. panel_destroy (WPanel * p)
  1216. {
  1217. size_t i;
  1218. if (panels_options.auto_save_setup)
  1219. {
  1220. char *name;
  1221. name = panel_save_name (p);
  1222. panel_save_setup (p, name);
  1223. g_free (name);
  1224. }
  1225. panel_clean_dir (p);
  1226. /* clean history */
  1227. if (p->dir_history != NULL)
  1228. {
  1229. /* directory history is already saved before this moment */
  1230. p->dir_history = g_list_first (p->dir_history);
  1231. g_list_free_full (p->dir_history, g_free);
  1232. }
  1233. g_free (p->hist_name);
  1234. delete_format (p->format);
  1235. delete_format (p->status_format);
  1236. g_free (p->user_format);
  1237. for (i = 0; i < LIST_FORMATS; i++)
  1238. g_free (p->user_status_format[i]);
  1239. g_free (p->dir.list);
  1240. g_free (p->panel_name);
  1241. vfs_path_free (p->lwd_vpath);
  1242. vfs_path_free (p->cwd_vpath);
  1243. }
  1244. /* --------------------------------------------------------------------------------------------- */
  1245. static inline void
  1246. panel_format_modified (WPanel * panel)
  1247. {
  1248. panel->format_modified = 1;
  1249. }
  1250. /* --------------------------------------------------------------------------------------------- */
  1251. static void
  1252. panel_paint_sort_info (const WPanel * panel)
  1253. {
  1254. if (*panel->sort_field->hotkey != '\0')
  1255. {
  1256. const char *sort_sign =
  1257. panel->sort_info.reverse ? panel_sort_up_sign : panel_sort_down_sign;
  1258. char *str;
  1259. str = g_strdup_printf ("%s%s", sort_sign, Q_ (panel->sort_field->hotkey));
  1260. widget_move (panel, 1, 1);
  1261. tty_print_string (str);
  1262. g_free (str);
  1263. }
  1264. }
  1265. /* --------------------------------------------------------------------------------------------- */
  1266. static const char *
  1267. panel_get_title_without_hotkey (const char *title)
  1268. {
  1269. static char translated_title[BUF_TINY];
  1270. if (title == NULL || title[0] == '\0')
  1271. translated_title[0] = '\0';
  1272. else
  1273. {
  1274. char *hkey;
  1275. g_snprintf (translated_title, sizeof (translated_title), "%s", _(title));
  1276. hkey = strchr (translated_title, '&');
  1277. if (hkey != NULL && hkey[1] != '\0')
  1278. memmove (hkey, hkey + 1, strlen (hkey));
  1279. }
  1280. return translated_title;
  1281. }
  1282. /* --------------------------------------------------------------------------------------------- */
  1283. static void
  1284. panel_print_header (const WPanel * panel)
  1285. {
  1286. const Widget *w = CONST_WIDGET (panel);
  1287. int y, x;
  1288. int i;
  1289. GString *format_txt;
  1290. widget_move (w, 1, 1);
  1291. tty_getyx (&y, &x);
  1292. tty_setcolor (NORMAL_COLOR);
  1293. tty_draw_hline (y, x, ' ', w->cols - 2);
  1294. format_txt = g_string_new ("");
  1295. for (i = 0; i < panel->list_cols; i++)
  1296. {
  1297. format_e *format;
  1298. for (format = panel->format; format != NULL; format = format->next)
  1299. {
  1300. if (format->string_fn != NULL)
  1301. {
  1302. g_string_set_size (format_txt, 0);
  1303. if (panel->list_format == list_long
  1304. && strcmp (format->id, panel->sort_field->id) == 0)
  1305. g_string_append (format_txt,
  1306. panel->sort_info.reverse
  1307. ? panel_sort_up_sign : panel_sort_down_sign);
  1308. g_string_append (format_txt, format->title);
  1309. if (panel->filter != NULL && strcmp (format->id, "name") == 0)
  1310. {
  1311. g_string_append (format_txt, " [");
  1312. g_string_append (format_txt, panel->filter);
  1313. g_string_append (format_txt, "]");
  1314. }
  1315. tty_setcolor (HEADER_COLOR);
  1316. tty_print_string (str_fit_to_term (format_txt->str, format->field_len,
  1317. J_CENTER_LEFT));
  1318. }
  1319. else
  1320. {
  1321. tty_setcolor (NORMAL_COLOR);
  1322. tty_print_one_vline (TRUE);
  1323. }
  1324. }
  1325. if (i < panel->list_cols - 1)
  1326. {
  1327. tty_setcolor (NORMAL_COLOR);
  1328. tty_print_one_vline (TRUE);
  1329. }
  1330. }
  1331. g_string_free (format_txt, TRUE);
  1332. if (panel->list_format != list_long)
  1333. panel_paint_sort_info (panel);
  1334. }
  1335. /* --------------------------------------------------------------------------------------------- */
  1336. static const char *
  1337. parse_panel_size (WPanel * panel, const char *format, gboolean isstatus)
  1338. {
  1339. panel_display_t frame = frame_half;
  1340. format = skip_separators (format);
  1341. if (strncmp (format, "full", 4) == 0)
  1342. {
  1343. frame = frame_full;
  1344. format += 4;
  1345. }
  1346. else if (strncmp (format, "half", 4) == 0)
  1347. {
  1348. frame = frame_half;
  1349. format += 4;
  1350. }
  1351. if (!isstatus)
  1352. {
  1353. panel->frame_size = frame;
  1354. panel->list_cols = 1;
  1355. }
  1356. /* Now, the optional column specifier */
  1357. format = skip_separators (format);
  1358. if (g_ascii_isdigit (*format))
  1359. {
  1360. if (!isstatus)
  1361. {
  1362. panel->list_cols = g_ascii_digit_value (*format);
  1363. if (panel->list_cols < 1)
  1364. panel->list_cols = 1;
  1365. }
  1366. format++;
  1367. }
  1368. if (!isstatus)
  1369. panel_update_cols (WIDGET (panel), panel->frame_size);
  1370. return skip_separators (format);
  1371. }
  1372. /* Format is:
  1373. all := panel_format? format
  1374. panel_format := [full|half] [1-9]
  1375. format := one_format_e
  1376. | format , one_format_e
  1377. one_format_e := just format.id [opt_size]
  1378. just := [<=>]
  1379. opt_size := : size [opt_expand]
  1380. size := [0-9]+
  1381. opt_expand := +
  1382. */
  1383. /* --------------------------------------------------------------------------------------------- */
  1384. static format_e *
  1385. parse_display_format (WPanel * panel, const char *format, char **error, gboolean isstatus,
  1386. int *res_total_cols)
  1387. {
  1388. format_e *darr, *old = NULL, *home = NULL; /* The formats we return */
  1389. int total_cols = 0; /* Used columns by the format */
  1390. size_t i;
  1391. static size_t i18n_timelength = 0; /* flag: check ?Time length at startup */
  1392. *error = NULL;
  1393. if (i18n_timelength == 0)
  1394. {
  1395. i18n_timelength = i18n_checktimelength (); /* Musn't be 0 */
  1396. for (i = 0; panel_fields[i].id != NULL; i++)
  1397. if (strcmp ("time", panel_fields[i].id + 1) == 0)
  1398. panel_fields[i].min_size = i18n_timelength;
  1399. }
  1400. /*
  1401. * This makes sure that the panel and mini status full/half mode
  1402. * setting is equal
  1403. */
  1404. format = parse_panel_size (panel, format, isstatus);
  1405. while (*format != '\0')
  1406. { /* format can be an empty string */
  1407. align_crt_t justify; /* Which mode. */
  1408. gboolean set_justify = TRUE; /* flag: set justification mode? */
  1409. gboolean found = FALSE;
  1410. darr = g_new0 (format_e, 1);
  1411. /* I'm so ugly, don't look at me :-) */
  1412. if (home == NULL)
  1413. home = old = darr;
  1414. old->next = darr;
  1415. darr->next = NULL;
  1416. old = darr;
  1417. format = skip_separators (format);
  1418. switch (*format)
  1419. {
  1420. case '<':
  1421. justify = J_LEFT;
  1422. format = skip_separators (format + 1);
  1423. break;
  1424. case '=':
  1425. justify = J_CENTER;
  1426. format = skip_separators (format + 1);
  1427. break;
  1428. case '>':
  1429. justify = J_RIGHT;
  1430. format = skip_separators (format + 1);
  1431. break;
  1432. default:
  1433. justify = J_LEFT;
  1434. set_justify = FALSE;
  1435. break;
  1436. }
  1437. for (i = 0; panel_fields[i].id != NULL; i++)
  1438. {
  1439. size_t klen;
  1440. klen = strlen (panel_fields[i].id);
  1441. if (strncmp (format, panel_fields[i].id, klen) != 0)
  1442. continue;
  1443. format += klen;
  1444. darr->requested_field_len = panel_fields[i].min_size;
  1445. darr->string_fn = panel_fields[i].string_fn;
  1446. darr->title = g_strdup (panel_get_title_without_hotkey (panel_fields[i].title_hotkey));
  1447. darr->id = panel_fields[i].id;
  1448. darr->expand = panel_fields[i].expands;
  1449. darr->just_mode = panel_fields[i].default_just;
  1450. if (set_justify)
  1451. {
  1452. if (IS_FIT (darr->just_mode))
  1453. darr->just_mode = MAKE_FIT (justify);
  1454. else
  1455. darr->just_mode = justify;
  1456. }
  1457. found = TRUE;
  1458. format = skip_separators (format);
  1459. /* If we have a size specifier */
  1460. if (*format == ':')
  1461. {
  1462. int req_length;
  1463. /* If the size was specified, we don't want
  1464. * auto-expansion by default
  1465. */
  1466. darr->expand = FALSE;
  1467. format++;
  1468. req_length = atoi (format);
  1469. darr->requested_field_len = req_length;
  1470. format = skip_numbers (format);
  1471. /* Now, if they insist on expansion */
  1472. if (*format == '+')
  1473. {
  1474. darr->expand = TRUE;
  1475. format++;
  1476. }
  1477. }
  1478. break;
  1479. }
  1480. if (!found)
  1481. {
  1482. size_t pos;
  1483. char *tmp_format;
  1484. pos = strlen (format);
  1485. if (pos > 8)
  1486. pos = 8;
  1487. tmp_format = g_strndup (format, pos);
  1488. delete_format (home);
  1489. *error =
  1490. g_strconcat (_("Unknown tag on display format:"), " ", tmp_format, (char *) NULL);
  1491. g_free (tmp_format);
  1492. return NULL;
  1493. }
  1494. total_cols += darr->requested_field_len;
  1495. }
  1496. *res_total_cols = total_cols;
  1497. return home;
  1498. }
  1499. /* --------------------------------------------------------------------------------------------- */
  1500. static format_e *
  1501. use_display_format (WPanel * panel, const char *format, char **error, gboolean isstatus)
  1502. {
  1503. #define MAX_EXPAND 4
  1504. int expand_top = 0; /* Max used element in expand */
  1505. int usable_columns; /* Usable columns in the panel */
  1506. int total_cols = 0;
  1507. format_e *darr, *home;
  1508. if (format == NULL)
  1509. format = DEFAULT_USER_FORMAT;
  1510. home = parse_display_format (panel, format, error, isstatus, &total_cols);
  1511. if (*error != NULL)
  1512. return NULL;
  1513. panel->dirty = 1;
  1514. usable_columns = WIDGET (panel)->cols - 2;
  1515. /* Status needn't to be split */
  1516. if (!isstatus)
  1517. {
  1518. usable_columns /= panel->list_cols;
  1519. if (panel->list_cols > 1)
  1520. usable_columns--;
  1521. }
  1522. /* Look for the expandable fields and set field_len based on the requested field len */
  1523. for (darr = home; darr != NULL && expand_top < MAX_EXPAND; darr = darr->next)
  1524. {
  1525. darr->field_len = darr->requested_field_len;
  1526. if (darr->expand)
  1527. expand_top++;
  1528. }
  1529. /* If we used more columns than the available columns, adjust that */
  1530. if (total_cols > usable_columns)
  1531. {
  1532. int dif;
  1533. int pdif = 0;
  1534. dif = total_cols - usable_columns;
  1535. while (dif != 0 && pdif != dif)
  1536. {
  1537. pdif = dif;
  1538. for (darr = home; darr; darr = darr->next)
  1539. if (dif != 0 && darr->field_len != 1)
  1540. {
  1541. darr->field_len--;
  1542. dif--;
  1543. }
  1544. }
  1545. total_cols = usable_columns; /* give up, the rest should be truncated */
  1546. }
  1547. /* Expand the available space */
  1548. if (usable_columns > total_cols && expand_top != 0)
  1549. {
  1550. int i;
  1551. int spaces = (usable_columns - total_cols) / expand_top;
  1552. for (i = 0, darr = home; darr && (i < expand_top); darr = darr->next)
  1553. if (darr->expand)
  1554. {
  1555. darr->field_len += spaces;
  1556. if (i == 0)
  1557. darr->field_len += (usable_columns - total_cols) % expand_top;
  1558. i++;
  1559. }
  1560. }
  1561. return home;
  1562. }
  1563. /* --------------------------------------------------------------------------------------------- */
  1564. /** Given the panel->view_type returns the format string to be parsed */
  1565. static const char *
  1566. panel_format (WPanel * panel)
  1567. {
  1568. switch (panel->list_format)
  1569. {
  1570. case list_long:
  1571. return "full perm space nlink space owner space group space size space mtime space name";
  1572. case list_brief:
  1573. {
  1574. static char format[BUF_TINY];
  1575. int brief_cols = panel->brief_cols;
  1576. if (brief_cols < 1)
  1577. brief_cols = 2;
  1578. if (brief_cols > 9)
  1579. brief_cols = 9;
  1580. g_snprintf (format, sizeof (format), "half %d type name", brief_cols);
  1581. return format;
  1582. }
  1583. case list_user:
  1584. return panel->user_format;
  1585. default:
  1586. case list_full:
  1587. return "half type name | size | mtime";
  1588. }
  1589. }
  1590. /* --------------------------------------------------------------------------------------------- */
  1591. static const char *
  1592. mini_status_format (WPanel * panel)
  1593. {
  1594. if (panel->user_mini_status)
  1595. return panel->user_status_format[panel->list_format];
  1596. switch (panel->list_format)
  1597. {
  1598. case list_long:
  1599. return "full perm space nlink space owner space group space size space mtime space name";
  1600. case list_brief:
  1601. return "half type name space bsize space perm space";
  1602. case list_full:
  1603. return "half type name";
  1604. default:
  1605. case list_user:
  1606. return panel->user_format;
  1607. }
  1608. }
  1609. /* */
  1610. /* Panel operation commands */
  1611. /* */
  1612. /* --------------------------------------------------------------------------------------------- */
  1613. /** Used to emulate Lynx's entering leaving a directory with the arrow keys */
  1614. static cb_ret_t
  1615. maybe_cd (gboolean move_up_dir)
  1616. {
  1617. if (panels_options.navigate_with_arrows && (cmdline->buffer[0] == '\0'))
  1618. {
  1619. if (move_up_dir)
  1620. {
  1621. vfs_path_t *up_dir;
  1622. up_dir = vfs_path_from_str ("..");
  1623. do_cd (up_dir, cd_exact);
  1624. vfs_path_free (up_dir);
  1625. return MSG_HANDLED;
  1626. }
  1627. if (S_ISDIR (selection (current_panel)->st.st_mode)
  1628. || link_isdir (selection (current_panel)))
  1629. {
  1630. vfs_path_t *vpath;
  1631. vpath = vfs_path_from_str (selection (current_panel)->fname);
  1632. do_cd (vpath, cd_exact);
  1633. vfs_path_free (vpath);
  1634. return MSG_HANDLED;
  1635. }
  1636. }
  1637. return MSG_NOT_HANDLED;
  1638. }
  1639. /* --------------------------------------------------------------------------------------------- */
  1640. /* if command line is empty then do 'cd ..' */
  1641. static cb_ret_t
  1642. force_maybe_cd (void)
  1643. {
  1644. if (cmdline->buffer[0] == '\0')
  1645. {
  1646. vfs_path_t *up_dir = vfs_path_from_str ("..");
  1647. do_cd (up_dir, cd_exact);
  1648. vfs_path_free (up_dir);
  1649. return MSG_HANDLED;
  1650. }
  1651. return MSG_NOT_HANDLED;
  1652. }
  1653. /* --------------------------------------------------------------------------------------------- */
  1654. static inline void
  1655. unselect_item (WPanel * panel)
  1656. {
  1657. repaint_file (panel, panel->selected, TRUE, 2 * selection (panel)->f.marked, FALSE);
  1658. }
  1659. /* --------------------------------------------------------------------------------------------- */
  1660. /** Select/unselect all the files like a current file by extension */
  1661. static void
  1662. panel_select_ext_cmd (void)
  1663. {
  1664. gboolean do_select = !selection (current_panel)->f.marked;
  1665. char *filename = selection (current_panel)->fname;
  1666. char *reg_exp, *cur_file_ext;
  1667. mc_search_t *search;
  1668. int i;
  1669. if (filename == NULL)
  1670. return;
  1671. cur_file_ext = strutils_regex_escape (extension (filename));
  1672. if (cur_file_ext[0] != '\0')
  1673. reg_exp = g_strconcat ("^.*\\.", cur_file_ext, "$", (char *) NULL);
  1674. else
  1675. reg_exp = g_strdup ("^[^\\.]+$");
  1676. g_free (cur_file_ext);
  1677. search = mc_search_new (reg_exp, NULL);
  1678. search->search_type = MC_SEARCH_T_REGEX;
  1679. search->is_case_sensitive = FALSE;
  1680. for (i = 0; i < current_panel->dir.len; i++)
  1681. {
  1682. file_entry_t *file_entry = &current_panel->dir.list[i];
  1683. if (DIR_IS_DOTDOT (file_entry->fname) || S_ISDIR (file_entry->st.st_mode))
  1684. continue;
  1685. if (!mc_search_run (search, file_entry->fname, 0, file_entry->fnamelen, NULL))
  1686. continue;
  1687. do_file_mark (current_panel, i, do_select);
  1688. }
  1689. mc_search_free (search);
  1690. g_free (reg_exp);
  1691. }
  1692. /* --------------------------------------------------------------------------------------------- */
  1693. static int
  1694. panel_selected_at_half (const WPanel * panel)
  1695. {
  1696. int lines, top;
  1697. lines = panel_lines (panel);
  1698. /* define top file of column */
  1699. top = panel->top_file;
  1700. if (panel->list_cols > 1)
  1701. top += lines * ((panel->selected - top) / lines);
  1702. return (panel->selected - top - lines / 2);
  1703. }
  1704. /* --------------------------------------------------------------------------------------------- */
  1705. static void
  1706. move_down (WPanel * panel)
  1707. {
  1708. int items;
  1709. if (panel->selected + 1 == panel->dir.len)
  1710. return;
  1711. unselect_item (panel);
  1712. panel->selected++;
  1713. items = panel_items (panel);
  1714. if (panels_options.scroll_pages && panel->selected - panel->top_file == items)
  1715. {
  1716. /* Scroll window half screen */
  1717. panel->top_file += items / 2;
  1718. if (panel->top_file > panel->dir.len - items)
  1719. panel->top_file = panel->dir.len - items;
  1720. paint_dir (panel);
  1721. }
  1722. else if (panels_options.scroll_center && panel_selected_at_half (panel) > 0)
  1723. {
  1724. /* Scroll window when cursor is halfway down */
  1725. panel->top_file++;
  1726. if (panel->top_file > panel->dir.len - items)
  1727. panel->top_file = panel->dir.len - items;
  1728. }
  1729. select_item (panel);
  1730. }
  1731. /* --------------------------------------------------------------------------------------------- */
  1732. static void
  1733. move_up (WPanel * panel)
  1734. {
  1735. if (panel->selected == 0)
  1736. return;
  1737. unselect_item (panel);
  1738. panel->selected--;
  1739. if (panels_options.scroll_pages && panel->selected < panel->top_file)
  1740. {
  1741. /* Scroll window half screen */
  1742. panel->top_file -= panel_items (panel) / 2;
  1743. if (panel->top_file < 0)
  1744. panel->top_file = 0;
  1745. paint_dir (panel);
  1746. }
  1747. else if (panels_options.scroll_center && panel_selected_at_half (panel) < 0)
  1748. {
  1749. /* Scroll window when cursor is halfway up */
  1750. panel->top_file--;
  1751. if (panel->top_file < 0)
  1752. panel->top_file = 0;
  1753. }
  1754. select_item (panel);
  1755. }
  1756. /* --------------------------------------------------------------------------------------------- */
  1757. /** Changes the selection by lines (may be negative) */
  1758. static void
  1759. move_selection (WPanel * panel, int lines)
  1760. {
  1761. int new_pos;
  1762. gboolean adjust = FALSE;
  1763. new_pos = panel->selected + lines;
  1764. if (new_pos >= panel->dir.len)
  1765. new_pos = panel->dir.len - 1;
  1766. if (new_pos < 0)
  1767. new_pos = 0;
  1768. unselect_item (panel);
  1769. panel->selected = new_pos;
  1770. if (panel->selected - panel->top_file >= panel_items (panel))
  1771. {
  1772. panel->top_file += lines;
  1773. adjust = TRUE;
  1774. }
  1775. if (panel->selected - panel->top_file < 0)
  1776. {
  1777. panel->top_file += lines;
  1778. adjust = TRUE;
  1779. }
  1780. if (adjust)
  1781. {
  1782. if (panel->top_file > panel->selected)
  1783. panel->top_file = panel->selected;
  1784. if (panel->top_file < 0)
  1785. panel->top_file = 0;
  1786. paint_dir (panel);
  1787. }
  1788. select_item (panel);
  1789. }
  1790. /* --------------------------------------------------------------------------------------------- */
  1791. static cb_ret_t
  1792. move_left (WPanel * panel)
  1793. {
  1794. if (panel->list_cols > 1)
  1795. {
  1796. move_selection (panel, -panel_lines (panel));
  1797. return MSG_HANDLED;
  1798. }
  1799. return maybe_cd (TRUE); /* cd .. */
  1800. }
  1801. /* --------------------------------------------------------------------------------------------- */
  1802. static cb_ret_t
  1803. move_right (WPanel * panel)
  1804. {
  1805. if (panel->list_cols > 1)
  1806. {
  1807. move_selection (panel, panel_lines (panel));
  1808. return MSG_HANDLED;
  1809. }
  1810. return maybe_cd (FALSE); /* cd (selection) */
  1811. }
  1812. /* --------------------------------------------------------------------------------------------- */
  1813. static void
  1814. prev_page (WPanel * panel)
  1815. {
  1816. int items;
  1817. if (!panel->selected && !panel->top_file)
  1818. return;
  1819. unselect_item (panel);
  1820. items = panel_items (panel);
  1821. if (panel->top_file < items)
  1822. items = panel->top_file;
  1823. if (items == 0)
  1824. panel->selected = 0;
  1825. else
  1826. panel->selected -= items;
  1827. panel->top_file -= items;
  1828. select_item (panel);
  1829. paint_dir (panel);
  1830. }
  1831. /* --------------------------------------------------------------------------------------------- */
  1832. static void
  1833. goto_parent_dir (WPanel * panel)
  1834. {
  1835. if (!panel->is_panelized)
  1836. {
  1837. vfs_path_t *up_dir;
  1838. up_dir = vfs_path_from_str ("..");
  1839. do_cd (up_dir, cd_exact);
  1840. vfs_path_free (up_dir);
  1841. }
  1842. else
  1843. {
  1844. char *fname = panel->dir.list[panel->selected].fname;
  1845. const char *bname;
  1846. vfs_path_t *dname_vpath;
  1847. if (g_path_is_absolute (fname))
  1848. fname = g_strdup (fname);
  1849. else
  1850. fname =
  1851. mc_build_filename (vfs_path_as_str (panelized_panel.root_vpath), fname,
  1852. (char *) NULL);
  1853. bname = x_basename (fname);
  1854. if (bname == fname)
  1855. dname_vpath = vfs_path_from_str (".");
  1856. else
  1857. {
  1858. char *dname;
  1859. dname = g_strndup (fname, bname - fname);
  1860. dname_vpath = vfs_path_from_str (dname);
  1861. g_free (dname);
  1862. }
  1863. do_cd (dname_vpath, cd_exact);
  1864. try_to_select (panel, bname);
  1865. vfs_path_free (dname_vpath);
  1866. g_free (fname);
  1867. }
  1868. }
  1869. /* --------------------------------------------------------------------------------------------- */
  1870. static void
  1871. next_page (WPanel * panel)
  1872. {
  1873. int items;
  1874. if (panel->selected == panel->dir.len - 1)
  1875. return;
  1876. unselect_item (panel);
  1877. items = panel_items (panel);
  1878. if (panel->top_file > panel->dir.len - 2 * items)
  1879. items = panel->dir.len - items - panel->top_file;
  1880. if (panel->top_file + items < 0)
  1881. items = -panel->top_file;
  1882. if (items == 0)
  1883. panel->selected = panel->dir.len - 1;
  1884. else
  1885. panel->selected += items;
  1886. panel->top_file += items;
  1887. select_item (panel);
  1888. paint_dir (panel);
  1889. }
  1890. /* --------------------------------------------------------------------------------------------- */
  1891. static void
  1892. goto_child_dir (WPanel * panel)
  1893. {
  1894. if ((S_ISDIR (selection (panel)->st.st_mode) || link_isdir (selection (panel))))
  1895. {
  1896. vfs_path_t *vpath;
  1897. vpath = vfs_path_from_str (selection (panel)->fname);
  1898. do_cd (vpath, cd_exact);
  1899. vfs_path_free (vpath);
  1900. }
  1901. }
  1902. /* --------------------------------------------------------------------------------------------- */
  1903. static void
  1904. goto_top_file (WPanel * panel)
  1905. {
  1906. unselect_item (panel);
  1907. panel->selected = panel->top_file;
  1908. select_item (panel);
  1909. }
  1910. /* --------------------------------------------------------------------------------------------- */
  1911. static void
  1912. goto_middle_file (WPanel * panel)
  1913. {
  1914. unselect_item (panel);
  1915. panel->selected = panel->top_file + panel_items (panel) / 2;
  1916. select_item (panel);
  1917. }
  1918. /* --------------------------------------------------------------------------------------------- */
  1919. static void
  1920. goto_bottom_file (WPanel * panel)
  1921. {
  1922. unselect_item (panel);
  1923. panel->selected = panel->top_file + panel_items (panel) - 1;
  1924. select_item (panel);
  1925. }
  1926. /* --------------------------------------------------------------------------------------------- */
  1927. static void
  1928. move_home (WPanel * panel)
  1929. {
  1930. if (panel->selected == 0)
  1931. return;
  1932. unselect_item (panel);
  1933. if (panels_options.torben_fj_mode)
  1934. {
  1935. int middle_pos = panel->top_file + panel_items (panel) / 2;
  1936. if (panel->selected > middle_pos)
  1937. {
  1938. goto_middle_file (panel);
  1939. return;
  1940. }
  1941. if (panel->selected != panel->top_file)
  1942. {
  1943. goto_top_file (panel);
  1944. return;
  1945. }
  1946. }
  1947. panel->top_file = 0;
  1948. panel->selected = 0;
  1949. paint_dir (panel);
  1950. select_item (panel);
  1951. }
  1952. /* --------------------------------------------------------------------------------------------- */
  1953. static void
  1954. move_end (WPanel * panel)
  1955. {
  1956. if (panel->selected == panel->dir.len - 1)
  1957. return;
  1958. unselect_item (panel);
  1959. if (panels_options.torben_fj_mode)
  1960. {
  1961. int items, middle_pos;
  1962. items = panel_items (panel);
  1963. middle_pos = panel->top_file + items / 2;
  1964. if (panel->selected < middle_pos)
  1965. {
  1966. goto_middle_file (panel);
  1967. return;
  1968. }
  1969. if (panel->selected != panel->top_file + items - 1)
  1970. {
  1971. goto_bottom_file (panel);
  1972. return;
  1973. }
  1974. }
  1975. panel->selected = panel->dir.len - 1;
  1976. paint_dir (panel);
  1977. select_item (panel);
  1978. }
  1979. /* --------------------------------------------------------------------------------------------- */
  1980. static void
  1981. do_mark_file (WPanel * panel, mark_act_t do_move)
  1982. {
  1983. do_file_mark (panel, panel->selected, selection (panel)->f.marked ? 0 : 1);
  1984. if ((panels_options.mark_moves_down && do_move == MARK_DOWN) || do_move == MARK_FORCE_DOWN)
  1985. move_down (panel);
  1986. else if (do_move == MARK_FORCE_UP)
  1987. move_up (panel);
  1988. }
  1989. /* --------------------------------------------------------------------------------------------- */
  1990. static inline void
  1991. mark_file (WPanel * panel)
  1992. {
  1993. do_mark_file (panel, MARK_DOWN);
  1994. }
  1995. /* --------------------------------------------------------------------------------------------- */
  1996. static inline void
  1997. mark_file_up (WPanel * panel)
  1998. {
  1999. do_mark_file (panel, MARK_FORCE_UP);
  2000. }
  2001. /* --------------------------------------------------------------------------------------------- */
  2002. static inline void
  2003. mark_file_down (WPanel * panel)
  2004. {
  2005. do_mark_file (panel, MARK_FORCE_DOWN);
  2006. }
  2007. /* --------------------------------------------------------------------------------------------- */
  2008. static void
  2009. mark_file_right (WPanel * panel)
  2010. {
  2011. int lines;
  2012. if (state_mark < 0)
  2013. state_mark = selection (panel)->f.marked ? 0 : 1;
  2014. lines = panel_lines (panel);
  2015. lines = MIN (lines, panel->dir.len - panel->selected - 1);
  2016. for (; lines != 0; lines--)
  2017. {
  2018. do_file_mark (panel, panel->selected, state_mark);
  2019. move_down (panel);
  2020. }
  2021. do_file_mark (panel, panel->selected, state_mark);
  2022. }
  2023. /* --------------------------------------------------------------------------------------------- */
  2024. static void
  2025. mark_file_left (WPanel * panel)
  2026. {
  2027. int lines;
  2028. if (state_mark < 0)
  2029. state_mark = selection (panel)->f.marked ? 0 : 1;
  2030. lines = panel_lines (panel);
  2031. lines = MIN (lines, panel->selected + 1);
  2032. for (; lines != 0; lines--)
  2033. {
  2034. do_file_mark (panel, panel->selected, state_mark);
  2035. move_up (panel);
  2036. }
  2037. do_file_mark (panel, panel->selected, state_mark);
  2038. }
  2039. /* --------------------------------------------------------------------------------------------- */
  2040. static void
  2041. panel_select_unselect_files (WPanel * panel, const char *title, const char *history_name,
  2042. gboolean do_select)
  2043. {
  2044. gboolean files_only = (panels_options.select_flags & SELECT_FILES_ONLY) != 0;
  2045. gboolean case_sens = (panels_options.select_flags & SELECT_MATCH_CASE) != 0;
  2046. gboolean shell_patterns = (panels_options.select_flags & SELECT_SHELL_PATTERNS) != 0;
  2047. char *reg_exp;
  2048. mc_search_t *search;
  2049. int i;
  2050. quick_widget_t quick_widgets[] = {
  2051. /* *INDENT-OFF* */
  2052. QUICK_INPUT (INPUT_LAST_TEXT, history_name, &reg_exp, NULL,
  2053. FALSE, FALSE, INPUT_COMPLETE_FILENAMES),
  2054. QUICK_START_COLUMNS,
  2055. QUICK_CHECKBOX (N_("&Files only"), &files_only, NULL),
  2056. QUICK_CHECKBOX (N_("&Using shell patterns"), &shell_patterns, NULL),
  2057. QUICK_NEXT_COLUMN,
  2058. QUICK_CHECKBOX (N_("&Case sensitive"), &case_sens, NULL),
  2059. QUICK_STOP_COLUMNS,
  2060. QUICK_END
  2061. /* *INDENT-ON* */
  2062. };
  2063. quick_dialog_t qdlg = {
  2064. -1, -1, 50,
  2065. title, "[Select/Unselect Files]",
  2066. quick_widgets, NULL, NULL
  2067. };
  2068. if (quick_dialog (&qdlg) == B_CANCEL)
  2069. return;
  2070. if (reg_exp == NULL || *reg_exp == '\0')
  2071. {
  2072. g_free (reg_exp);
  2073. return;
  2074. }
  2075. search = mc_search_new (reg_exp, NULL);
  2076. search->search_type = shell_patterns ? MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX;
  2077. search->is_entire_line = TRUE;
  2078. search->is_case_sensitive = case_sens;
  2079. for (i = 0; i < panel->dir.len; i++)
  2080. {
  2081. if (DIR_IS_DOTDOT (panel->dir.list[i].fname))
  2082. continue;
  2083. if (S_ISDIR (panel->dir.list[i].st.st_mode) && files_only)
  2084. continue;
  2085. if (mc_search_run (search, panel->dir.list[i].fname, 0, panel->dir.list[i].fnamelen, NULL))
  2086. do_file_mark (panel, i, do_select);
  2087. }
  2088. mc_search_free (search);
  2089. g_free (reg_exp);
  2090. /* result flags */
  2091. panels_options.select_flags = 0;
  2092. if (case_sens)
  2093. panels_options.select_flags |= SELECT_MATCH_CASE;
  2094. if (files_only)
  2095. panels_options.select_flags |= SELECT_FILES_ONLY;
  2096. if (shell_patterns)
  2097. panels_options.select_flags |= SELECT_SHELL_PATTERNS;
  2098. }
  2099. /* --------------------------------------------------------------------------------------------- */
  2100. static void
  2101. panel_select_files (WPanel * panel)
  2102. {
  2103. panel_select_unselect_files (panel, _("Select"), ":select_cmd: Select ", TRUE);
  2104. }
  2105. /* --------------------------------------------------------------------------------------------- */
  2106. static void
  2107. panel_unselect_files (WPanel * panel)
  2108. {
  2109. panel_select_unselect_files (panel, _("Unselect"), ":unselect_cmd: Unselect ", FALSE);
  2110. }
  2111. /* --------------------------------------------------------------------------------------------- */
  2112. static void
  2113. panel_select_invert_files (WPanel * panel)
  2114. {
  2115. int i;
  2116. for (i = 0; i < panel->dir.len; i++)
  2117. {
  2118. file_entry_t *file = &panel->dir.list[i];
  2119. if (!panels_options.reverse_files_only || !S_ISDIR (file->st.st_mode))
  2120. do_file_mark (panel, i, !file->f.marked);
  2121. }
  2122. }
  2123. /* --------------------------------------------------------------------------------------------- */
  2124. /** Incremental search of a file name in the panel.
  2125. * @param panel instance of WPanel structure
  2126. * @param c_code key code
  2127. */
  2128. static void
  2129. do_search (WPanel * panel, int c_code)
  2130. {
  2131. size_t l;
  2132. int i, sel;
  2133. gboolean wrapped = FALSE;
  2134. char *act;
  2135. mc_search_t *search;
  2136. char *reg_exp, *esc_str;
  2137. gboolean is_found = FALSE;
  2138. l = strlen (panel->search_buffer);
  2139. if (c_code == KEY_BACKSPACE)
  2140. {
  2141. if (l != 0)
  2142. {
  2143. act = panel->search_buffer + l;
  2144. str_prev_noncomb_char (&act, panel->search_buffer);
  2145. act[0] = '\0';
  2146. }
  2147. panel->search_chpoint = 0;
  2148. }
  2149. else
  2150. {
  2151. if (c_code != 0 && (gsize) panel->search_chpoint < sizeof (panel->search_char))
  2152. {
  2153. panel->search_char[panel->search_chpoint] = c_code;
  2154. panel->search_chpoint++;
  2155. }
  2156. if (panel->search_chpoint > 0)
  2157. {
  2158. switch (str_is_valid_char (panel->search_char, panel->search_chpoint))
  2159. {
  2160. case -2:
  2161. return;
  2162. case -1:
  2163. panel->search_chpoint = 0;
  2164. return;
  2165. default:
  2166. if (l + panel->search_chpoint < sizeof (panel->search_buffer))
  2167. {
  2168. memcpy (panel->search_buffer + l, panel->search_char, panel->search_chpoint);
  2169. l += panel->search_chpoint;
  2170. *(panel->search_buffer + l) = '\0';
  2171. panel->search_chpoint = 0;
  2172. }
  2173. }
  2174. }
  2175. }
  2176. reg_exp = g_strdup_printf ("%s*", panel->search_buffer);
  2177. esc_str = strutils_escape (reg_exp, -1, ",|\\{}[]", TRUE);
  2178. search = mc_search_new (esc_str, NULL);
  2179. search->search_type = MC_SEARCH_T_GLOB;
  2180. search->is_entire_line = TRUE;
  2181. switch (panels_options.qsearch_mode)
  2182. {
  2183. case QSEARCH_CASE_SENSITIVE:
  2184. search->is_case_sensitive = TRUE;
  2185. break;
  2186. case QSEARCH_CASE_INSENSITIVE:
  2187. search->is_case_sensitive = FALSE;
  2188. break;
  2189. default:
  2190. search->is_case_sensitive = panel->sort_info.case_sensitive;
  2191. break;
  2192. }
  2193. sel = panel->selected;
  2194. for (i = panel->selected; !wrapped || i != panel->selected; i++)
  2195. {
  2196. if (i >= panel->dir.len)
  2197. {
  2198. i = 0;
  2199. if (wrapped)
  2200. break;
  2201. wrapped = TRUE;
  2202. }
  2203. if (mc_search_run (search, panel->dir.list[i].fname, 0, panel->dir.list[i].fnamelen, NULL))
  2204. {
  2205. sel = i;
  2206. is_found = TRUE;
  2207. break;
  2208. }
  2209. }
  2210. if (is_found)
  2211. {
  2212. unselect_item (panel);
  2213. panel->selected = sel;
  2214. select_item (panel);
  2215. widget_redraw (WIDGET (panel));
  2216. }
  2217. else if (c_code != KEY_BACKSPACE)
  2218. {
  2219. act = panel->search_buffer + l;
  2220. str_prev_noncomb_char (&act, panel->search_buffer);
  2221. act[0] = '\0';
  2222. }
  2223. mc_search_free (search);
  2224. g_free (reg_exp);
  2225. g_free (esc_str);
  2226. }
  2227. /* --------------------------------------------------------------------------------------------- */
  2228. /** Start new search.
  2229. * @param panel instance of WPanel structure
  2230. */
  2231. static void
  2232. start_search (WPanel * panel)
  2233. {
  2234. if (panel->searching)
  2235. {
  2236. if (panel->selected + 1 == panel->dir.len)
  2237. panel->selected = 0;
  2238. else
  2239. move_down (panel);
  2240. /* in case if there was no search string we need to recall
  2241. previous string, with which we ended previous searching */
  2242. if (panel->search_buffer[0] == '\0')
  2243. g_strlcpy (panel->search_buffer, panel->prev_search_buffer,
  2244. sizeof (panel->search_buffer));
  2245. do_search (panel, 0);
  2246. }
  2247. else
  2248. {
  2249. panel->searching = TRUE;
  2250. panel->search_buffer[0] = '\0';
  2251. panel->search_char[0] = '\0';
  2252. panel->search_chpoint = 0;
  2253. display_mini_info (panel);
  2254. mc_refresh ();
  2255. }
  2256. }
  2257. /* --------------------------------------------------------------------------------------------- */
  2258. static void
  2259. stop_search (WPanel * panel)
  2260. {
  2261. panel->searching = FALSE;
  2262. /* if user had overrdied search string, we need to store it
  2263. to the previous_search_buffer */
  2264. if (panel->search_buffer[0] != '\0')
  2265. g_strlcpy (panel->prev_search_buffer, panel->search_buffer,
  2266. sizeof (panel->prev_search_buffer));
  2267. display_mini_info (panel);
  2268. }
  2269. /* --------------------------------------------------------------------------------------------- */
  2270. /** Return TRUE if the Enter key has been processed, FALSE otherwise */
  2271. static gboolean
  2272. do_enter_on_file_entry (file_entry_t * fe)
  2273. {
  2274. vfs_path_t *full_name_vpath;
  2275. gboolean ok;
  2276. /*
  2277. * Directory or link to directory - change directory.
  2278. * Try the same for the entries on which mc_lstat() has failed.
  2279. */
  2280. if (S_ISDIR (fe->st.st_mode) || link_isdir (fe) || (fe->st.st_mode == 0))
  2281. {
  2282. vfs_path_t *fname_vpath;
  2283. fname_vpath = vfs_path_from_str (fe->fname);
  2284. if (!do_cd (fname_vpath, cd_exact))
  2285. message (D_ERROR, MSG_ERROR, _("Cannot change directory"));
  2286. vfs_path_free (fname_vpath);
  2287. return TRUE;
  2288. }
  2289. full_name_vpath = vfs_path_append_new (current_panel->cwd_vpath, fe->fname, (char *) NULL);
  2290. /* Try associated command */
  2291. ok = regex_command (full_name_vpath, "Open") != 0;
  2292. vfs_path_free (full_name_vpath);
  2293. if (ok)
  2294. return TRUE;
  2295. /* Check if the file is executable */
  2296. full_name_vpath = vfs_path_append_new (current_panel->cwd_vpath, fe->fname, (char *) NULL);
  2297. ok = (is_exe (fe->st.st_mode) && if_link_is_exe (full_name_vpath, fe));
  2298. vfs_path_free (full_name_vpath);
  2299. if (!ok)
  2300. return FALSE;
  2301. if (confirm_execute)
  2302. {
  2303. if (query_dialog
  2304. (_("The Midnight Commander"),
  2305. _("Do you really want to execute?"), D_NORMAL, 2, _("&Yes"), _("&No")) != 0)
  2306. return TRUE;
  2307. }
  2308. if (!vfs_current_is_local ())
  2309. {
  2310. int ret;
  2311. vfs_path_t *tmp_vpath;
  2312. tmp_vpath = vfs_path_append_new (vfs_get_raw_current_dir (), fe->fname, (char *) NULL);
  2313. ret = mc_setctl (tmp_vpath, VFS_SETCTL_RUN, NULL);
  2314. vfs_path_free (tmp_vpath);
  2315. /* We took action only if the dialog was shown or the execution
  2316. * was successful */
  2317. return confirm_execute || (ret == 0);
  2318. }
  2319. {
  2320. char *tmp, *cmd;
  2321. tmp = name_quote (fe->fname, FALSE);
  2322. cmd = g_strconcat (".", PATH_SEP_STR, tmp, (char *) NULL);
  2323. g_free (tmp);
  2324. shell_execute (cmd, 0);
  2325. g_free (cmd);
  2326. }
  2327. #ifdef HAVE_CHARSET
  2328. mc_global.source_codepage = default_source_codepage;
  2329. #endif
  2330. return TRUE;
  2331. }
  2332. /* --------------------------------------------------------------------------------------------- */
  2333. static inline gboolean
  2334. do_enter (WPanel * panel)
  2335. {
  2336. return do_enter_on_file_entry (selection (panel));
  2337. }
  2338. /* --------------------------------------------------------------------------------------------- */
  2339. static void
  2340. panel_cycle_listing_format (WPanel * panel)
  2341. {
  2342. panel->list_format = (panel->list_format + 1) % LIST_FORMATS;
  2343. if (set_panel_formats (panel) == 0)
  2344. do_refresh ();
  2345. }
  2346. /* --------------------------------------------------------------------------------------------- */
  2347. static void
  2348. chdir_other_panel (WPanel * panel)
  2349. {
  2350. const file_entry_t *entry = &panel->dir.list[panel->selected];
  2351. vfs_path_t *new_dir_vpath;
  2352. char *sel_entry = NULL;
  2353. if (get_other_type () != view_listing)
  2354. set_display_type (get_other_index (), view_listing);
  2355. if (S_ISDIR (entry->st.st_mode) || link_isdir (entry))
  2356. new_dir_vpath = vfs_path_append_new (panel->cwd_vpath, entry->fname, (char *) NULL);
  2357. else
  2358. {
  2359. new_dir_vpath = vfs_path_append_new (panel->cwd_vpath, "..", (char *) NULL);
  2360. sel_entry = strrchr (vfs_path_get_last_path_str (panel->cwd_vpath), PATH_SEP);
  2361. }
  2362. change_panel ();
  2363. do_cd (new_dir_vpath, cd_exact);
  2364. vfs_path_free (new_dir_vpath);
  2365. if (sel_entry)
  2366. try_to_select (current_panel, sel_entry);
  2367. change_panel ();
  2368. move_down (panel);
  2369. }
  2370. /* --------------------------------------------------------------------------------------------- */
  2371. /**
  2372. * Make the current directory of the current panel also the current
  2373. * directory of the other panel. Put the other panel to the listing
  2374. * mode if needed. If the current panel is panelized, the other panel
  2375. * doesn't become panelized.
  2376. */
  2377. static void
  2378. panel_sync_other (const WPanel * panel)
  2379. {
  2380. if (get_other_type () != view_listing)
  2381. set_display_type (get_other_index (), view_listing);
  2382. do_panel_cd (other_panel, current_panel->cwd_vpath, cd_exact);
  2383. /* try to select current filename on the other panel */
  2384. if (!panel->is_panelized)
  2385. try_to_select (other_panel, selection (panel)->fname);
  2386. }
  2387. /* --------------------------------------------------------------------------------------------- */
  2388. static void
  2389. chdir_to_readlink (WPanel * panel)
  2390. {
  2391. vfs_path_t *new_dir_vpath;
  2392. char buffer[MC_MAXPATHLEN];
  2393. int i;
  2394. struct stat st;
  2395. vfs_path_t *panel_fname_vpath;
  2396. gboolean ok;
  2397. if (get_other_type () != view_listing)
  2398. return;
  2399. if (!S_ISLNK (panel->dir.list[panel->selected].st.st_mode))
  2400. return;
  2401. i = readlink (selection (panel)->fname, buffer, MC_MAXPATHLEN - 1);
  2402. if (i < 0)
  2403. return;
  2404. panel_fname_vpath = vfs_path_from_str (selection (panel)->fname);
  2405. ok = (mc_stat (panel_fname_vpath, &st) >= 0);
  2406. vfs_path_free (panel_fname_vpath);
  2407. if (!ok)
  2408. return;
  2409. buffer[i] = 0;
  2410. if (!S_ISDIR (st.st_mode))
  2411. {
  2412. char *p;
  2413. p = strrchr (buffer, PATH_SEP);
  2414. if (p && !p[1])
  2415. {
  2416. *p = 0;
  2417. p = strrchr (buffer, PATH_SEP);
  2418. }
  2419. if (!p)
  2420. return;
  2421. p[1] = 0;
  2422. }
  2423. if (IS_PATH_SEP (*buffer))
  2424. new_dir_vpath = vfs_path_from_str (buffer);
  2425. else
  2426. new_dir_vpath = vfs_path_append_new (panel->cwd_vpath, buffer, (char *) NULL);
  2427. change_panel ();
  2428. do_cd (new_dir_vpath, cd_exact);
  2429. vfs_path_free (new_dir_vpath);
  2430. change_panel ();
  2431. move_down (panel);
  2432. }
  2433. /* --------------------------------------------------------------------------------------------- */
  2434. static gsize
  2435. panel_get_format_field_count (WPanel * panel)
  2436. {
  2437. format_e *format;
  2438. gsize lc_index;
  2439. for (lc_index = 0, format = panel->format; format != NULL; format = format->next, lc_index++)
  2440. ;
  2441. return lc_index;
  2442. }
  2443. /* --------------------------------------------------------------------------------------------- */
  2444. /**
  2445. function return 0 if not found and REAL_INDEX+1 if found
  2446. */
  2447. static gsize
  2448. panel_get_format_field_index_by_name (WPanel * panel, const char *name)
  2449. {
  2450. format_e *format;
  2451. gsize lc_index;
  2452. for (lc_index = 1, format = panel->format;
  2453. format != NULL && strcmp (format->title, name) != 0; format = format->next, lc_index++)
  2454. ;
  2455. if (format == NULL)
  2456. lc_index = 0;
  2457. return lc_index;
  2458. }
  2459. /* --------------------------------------------------------------------------------------------- */
  2460. static format_e *
  2461. panel_get_format_field_by_index (WPanel * panel, gsize lc_index)
  2462. {
  2463. format_e *format;
  2464. for (format = panel->format; format != NULL && lc_index != 0; format = format->next, lc_index--)
  2465. ;
  2466. return format;
  2467. }
  2468. /* --------------------------------------------------------------------------------------------- */
  2469. static const panel_field_t *
  2470. panel_get_sortable_field_by_format (WPanel * panel, gsize lc_index)
  2471. {
  2472. const panel_field_t *pfield;
  2473. format_e *format;
  2474. format = panel_get_format_field_by_index (panel, lc_index);
  2475. if (format == NULL)
  2476. return NULL;
  2477. pfield = panel_get_field_by_title (format->title);
  2478. if (pfield == NULL)
  2479. return NULL;
  2480. if (pfield->sort_routine == NULL)
  2481. return NULL;
  2482. return pfield;
  2483. }
  2484. /* --------------------------------------------------------------------------------------------- */
  2485. static void
  2486. panel_toggle_sort_order_prev (WPanel * panel)
  2487. {
  2488. gsize lc_index, i;
  2489. const char *title;
  2490. const panel_field_t *pfield = NULL;
  2491. title = panel_get_title_without_hotkey (panel->sort_field->title_hotkey);
  2492. lc_index = panel_get_format_field_index_by_name (panel, title);
  2493. if (lc_index > 1)
  2494. {
  2495. /* search for prev sortable column in panel format */
  2496. for (i = lc_index - 1;
  2497. i != 0 && (pfield = panel_get_sortable_field_by_format (panel, i - 1)) == NULL; i--)
  2498. ;
  2499. }
  2500. if (pfield == NULL)
  2501. {
  2502. /* Sortable field not found. Try to search in each array */
  2503. for (i = panel_get_format_field_count (panel);
  2504. i != 0 && (pfield = panel_get_sortable_field_by_format (panel, i - 1)) == NULL; i--)
  2505. ;
  2506. }
  2507. if (pfield != NULL)
  2508. {
  2509. panel->sort_field = pfield;
  2510. panel_set_sort_order (panel, pfield);
  2511. }
  2512. }
  2513. /* --------------------------------------------------------------------------------------------- */
  2514. static void
  2515. panel_toggle_sort_order_next (WPanel * panel)
  2516. {
  2517. gsize lc_index, i;
  2518. const panel_field_t *pfield = NULL;
  2519. gsize format_field_count;
  2520. const char *title;
  2521. format_field_count = panel_get_format_field_count (panel);
  2522. title = panel_get_title_without_hotkey (panel->sort_field->title_hotkey);
  2523. lc_index = panel_get_format_field_index_by_name (panel, title);
  2524. if (lc_index != 0 && lc_index != format_field_count)
  2525. {
  2526. /* search for prev sortable column in panel format */
  2527. for (i = lc_index;
  2528. i != format_field_count
  2529. && (pfield = panel_get_sortable_field_by_format (panel, i)) == NULL; i++)
  2530. ;
  2531. }
  2532. if (pfield == NULL)
  2533. {
  2534. /* Sortable field not found. Try to search in each array */
  2535. for (i = 0;
  2536. i != format_field_count
  2537. && (pfield = panel_get_sortable_field_by_format (panel, i)) == NULL; i++)
  2538. ;
  2539. }
  2540. if (pfield != NULL)
  2541. {
  2542. panel->sort_field = pfield;
  2543. panel_set_sort_order (panel, pfield);
  2544. }
  2545. }
  2546. /* --------------------------------------------------------------------------------------------- */
  2547. static void
  2548. panel_select_sort_order (WPanel * panel)
  2549. {
  2550. const panel_field_t *sort_order;
  2551. sort_order = sort_box (&panel->sort_info, panel->sort_field);
  2552. if (sort_order != NULL)
  2553. {
  2554. panel->sort_field = sort_order;
  2555. panel_set_sort_order (panel, sort_order);
  2556. }
  2557. }
  2558. /* --------------------------------------------------------------------------------------------- */
  2559. /**
  2560. * panel_content_scroll_left:
  2561. * @param panel the pointer to the panel on which we operate
  2562. *
  2563. * scroll long filename to the left (decrement scroll pointer)
  2564. *
  2565. */
  2566. static void
  2567. panel_content_scroll_left (WPanel * panel)
  2568. {
  2569. if (panel->content_shift > -1)
  2570. {
  2571. if (panel->content_shift > panel->max_shift)
  2572. panel->content_shift = panel->max_shift;
  2573. panel->content_shift--;
  2574. show_dir (panel);
  2575. paint_dir (panel);
  2576. }
  2577. }
  2578. /* --------------------------------------------------------------------------------------------- */
  2579. /**
  2580. * panel_content_scroll_right:
  2581. * @param panel the pointer to the panel on which we operate
  2582. *
  2583. * scroll long filename to the right (increment scroll pointer)
  2584. *
  2585. */
  2586. static void
  2587. panel_content_scroll_right (WPanel * panel)
  2588. {
  2589. if (panel->content_shift < 0 || panel->content_shift < panel->max_shift)
  2590. {
  2591. panel->content_shift++;
  2592. show_dir (panel);
  2593. paint_dir (panel);
  2594. }
  2595. }
  2596. /* --------------------------------------------------------------------------------------------- */
  2597. static void
  2598. panel_set_sort_type_by_id (WPanel * panel, const char *name)
  2599. {
  2600. if (strcmp (panel->sort_field->id, name) != 0)
  2601. {
  2602. const panel_field_t *sort_order;
  2603. sort_order = panel_get_field_by_id (name);
  2604. if (sort_order == NULL)
  2605. return;
  2606. panel->sort_field = sort_order;
  2607. }
  2608. else
  2609. panel->sort_info.reverse = !panel->sort_info.reverse;
  2610. panel_set_sort_order (panel, panel->sort_field);
  2611. }
  2612. /* --------------------------------------------------------------------------------------------- */
  2613. /**
  2614. * If we moved to the parent directory move the selection pointer to
  2615. * the old directory name; If we leave VFS dir, remove FS specificator.
  2616. *
  2617. * You do _NOT_ want to add any vfs aware code here. <pavel@ucw.cz>
  2618. */
  2619. static const char *
  2620. get_parent_dir_name (const vfs_path_t * cwd_vpath, const vfs_path_t * lwd_vpath)
  2621. {
  2622. size_t llen, clen;
  2623. const char *p, *cwd, *lwd;
  2624. llen = vfs_path_len (lwd_vpath);
  2625. clen = vfs_path_len (cwd_vpath);
  2626. if (llen <= clen)
  2627. return NULL;
  2628. cwd = vfs_path_as_str (cwd_vpath);
  2629. lwd = vfs_path_as_str (lwd_vpath);
  2630. p = g_strrstr (lwd, VFS_PATH_URL_DELIMITER);
  2631. if (p == NULL)
  2632. {
  2633. p = strrchr (lwd, PATH_SEP);
  2634. if ((p != NULL)
  2635. && (strncmp (cwd, lwd, (size_t) (p - lwd)) == 0)
  2636. && (clen == (size_t) (p - lwd) || (p == lwd && IS_PATH_SEP (cwd[0]) && cwd[1] == '\0')))
  2637. return (p + 1);
  2638. return NULL;
  2639. }
  2640. /* skip VFS prefix */
  2641. while (--p > lwd && !IS_PATH_SEP (*p))
  2642. ;
  2643. /* get last component */
  2644. while (--p > lwd && !IS_PATH_SEP (*p))
  2645. ;
  2646. /* return last component */
  2647. return (p != lwd || IS_PATH_SEP (*p)) ? p + 1 : p;
  2648. }
  2649. /* --------------------------------------------------------------------------------------------- */
  2650. /** Wrapper for do_subshell_chdir, check for availability of subshell */
  2651. static void
  2652. subshell_chdir (const vfs_path_t * vpath)
  2653. {
  2654. #ifdef ENABLE_SUBSHELL
  2655. if (mc_global.tty.use_subshell && vfs_current_is_local ())
  2656. do_subshell_chdir (vpath, FALSE);
  2657. #else /* ENABLE_SUBSHELL */
  2658. (void) vpath;
  2659. #endif /* ENABLE_SUBSHELL */
  2660. }
  2661. /* --------------------------------------------------------------------------------------------- */
  2662. /**
  2663. * Changes the current directory of the panel.
  2664. * Don't record change in the directory history.
  2665. */
  2666. static gboolean
  2667. _do_panel_cd (WPanel * panel, const vfs_path_t * new_dir_vpath, enum cd_enum cd_type)
  2668. {
  2669. vfs_path_t *olddir_vpath;
  2670. /* Convert *new_path to a suitable pathname, handle ~user */
  2671. if (cd_type == cd_parse_command)
  2672. {
  2673. const vfs_path_element_t *element;
  2674. element = vfs_path_get_by_index (new_dir_vpath, 0);
  2675. if (strcmp (element->path, "-") == 0)
  2676. new_dir_vpath = panel->lwd_vpath;
  2677. }
  2678. if (mc_chdir (new_dir_vpath) == -1)
  2679. return FALSE;
  2680. /* Success: save previous directory, shutdown status of previous dir */
  2681. olddir_vpath = vfs_path_clone (panel->cwd_vpath);
  2682. panel_set_lwd (panel, panel->cwd_vpath);
  2683. input_free_completions (cmdline);
  2684. vfs_path_free (panel->cwd_vpath);
  2685. vfs_setup_cwd ();
  2686. panel->cwd_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
  2687. vfs_release_path (olddir_vpath);
  2688. subshell_chdir (panel->cwd_vpath);
  2689. /* Reload current panel */
  2690. panel_clean_dir (panel);
  2691. dir_list_load (&panel->dir, panel->cwd_vpath, panel->sort_field->sort_routine,
  2692. &panel->sort_info, panel->filter);
  2693. try_to_select (panel, get_parent_dir_name (panel->cwd_vpath, olddir_vpath));
  2694. load_hint (FALSE);
  2695. panel->dirty = 1;
  2696. update_xterm_title_path ();
  2697. vfs_path_free (olddir_vpath);
  2698. return TRUE;
  2699. }
  2700. /* --------------------------------------------------------------------------------------------- */
  2701. static void
  2702. directory_history_next (WPanel * panel)
  2703. {
  2704. gboolean ok;
  2705. do
  2706. {
  2707. GList *next;
  2708. ok = TRUE;
  2709. next = g_list_next (panel->dir_history_current);
  2710. if (next != NULL)
  2711. {
  2712. vfs_path_t *data_vpath;
  2713. data_vpath = vfs_path_from_str ((char *) next->data);
  2714. ok = _do_panel_cd (panel, data_vpath, cd_exact);
  2715. vfs_path_free (data_vpath);
  2716. panel->dir_history_current = next;
  2717. }
  2718. /* skip directories that present in history but absent in file system */
  2719. }
  2720. while (!ok);
  2721. }
  2722. /* --------------------------------------------------------------------------------------------- */
  2723. static void
  2724. directory_history_prev (WPanel * panel)
  2725. {
  2726. gboolean ok;
  2727. do
  2728. {
  2729. GList *prev;
  2730. ok = TRUE;
  2731. prev = g_list_previous (panel->dir_history_current);
  2732. if (prev != NULL)
  2733. {
  2734. vfs_path_t *data_vpath;
  2735. data_vpath = vfs_path_from_str ((char *) prev->data);
  2736. ok = _do_panel_cd (panel, data_vpath, cd_exact);
  2737. vfs_path_free (data_vpath);
  2738. panel->dir_history_current = prev;
  2739. }
  2740. /* skip directories that present in history but absent in file system */
  2741. }
  2742. while (!ok);
  2743. }
  2744. /* --------------------------------------------------------------------------------------------- */
  2745. static void
  2746. directory_history_list (WPanel * panel)
  2747. {
  2748. char *s;
  2749. gboolean ok = FALSE;
  2750. size_t pos;
  2751. pos = g_list_position (panel->dir_history_current, panel->dir_history);
  2752. s = history_show (&panel->dir_history, WIDGET (panel), pos);
  2753. if (s != NULL)
  2754. {
  2755. vfs_path_t *s_vpath;
  2756. s_vpath = vfs_path_from_str (s);
  2757. ok = _do_panel_cd (panel, s_vpath, cd_exact);
  2758. if (ok)
  2759. directory_history_add (panel, panel->cwd_vpath);
  2760. else
  2761. message (D_ERROR, MSG_ERROR, _("Cannot change directory"));
  2762. vfs_path_free (s_vpath);
  2763. g_free (s);
  2764. }
  2765. if (!ok)
  2766. {
  2767. /* Since history is fully modified in history_show(), panel->dir_history actually
  2768. * points to the invalid place. Try restore current postition here. */
  2769. size_t i;
  2770. panel->dir_history_current = panel->dir_history;
  2771. for (i = 0; i <= pos; i++)
  2772. {
  2773. GList *prev;
  2774. prev = g_list_previous (panel->dir_history_current);
  2775. if (prev == NULL)
  2776. break;
  2777. panel->dir_history_current = prev;
  2778. }
  2779. }
  2780. }
  2781. /* --------------------------------------------------------------------------------------------- */
  2782. static cb_ret_t
  2783. panel_execute_cmd (WPanel * panel, long command)
  2784. {
  2785. int res = MSG_HANDLED;
  2786. if (command != CK_Search)
  2787. stop_search (panel);
  2788. switch (command)
  2789. {
  2790. case CK_Up:
  2791. case CK_Down:
  2792. case CK_Left:
  2793. case CK_Right:
  2794. case CK_Bottom:
  2795. case CK_Top:
  2796. case CK_PageDown:
  2797. case CK_PageUp:
  2798. /* reset state of marks flag */
  2799. state_mark = -1;
  2800. break;
  2801. default:
  2802. break;
  2803. }
  2804. switch (command)
  2805. {
  2806. case CK_CycleListingFormat:
  2807. panel_cycle_listing_format (panel);
  2808. break;
  2809. case CK_PanelOtherCd:
  2810. chdir_other_panel (panel);
  2811. break;
  2812. case CK_PanelOtherCdLink:
  2813. chdir_to_readlink (panel);
  2814. break;
  2815. case CK_CopySingle:
  2816. copy_cmd_local ();
  2817. break;
  2818. case CK_DeleteSingle:
  2819. delete_cmd_local ();
  2820. break;
  2821. case CK_Enter:
  2822. do_enter (panel);
  2823. break;
  2824. case CK_ViewRaw:
  2825. view_raw_cmd ();
  2826. break;
  2827. case CK_EditNew:
  2828. edit_cmd_new ();
  2829. break;
  2830. case CK_MoveSingle:
  2831. rename_cmd_local ();
  2832. break;
  2833. case CK_SelectInvert:
  2834. panel_select_invert_files (panel);
  2835. break;
  2836. case CK_Select:
  2837. panel_select_files (panel);
  2838. break;
  2839. case CK_SelectExt:
  2840. panel_select_ext_cmd ();
  2841. break;
  2842. case CK_Unselect:
  2843. panel_unselect_files (panel);
  2844. break;
  2845. case CK_PageDown:
  2846. next_page (panel);
  2847. break;
  2848. case CK_PageUp:
  2849. prev_page (panel);
  2850. break;
  2851. case CK_CdChild:
  2852. goto_child_dir (panel);
  2853. break;
  2854. case CK_CdParent:
  2855. goto_parent_dir (panel);
  2856. break;
  2857. case CK_History:
  2858. directory_history_list (panel);
  2859. break;
  2860. case CK_HistoryNext:
  2861. directory_history_next (panel);
  2862. break;
  2863. case CK_HistoryPrev:
  2864. directory_history_prev (panel);
  2865. break;
  2866. case CK_BottomOnScreen:
  2867. goto_bottom_file (panel);
  2868. break;
  2869. case CK_MiddleOnScreen:
  2870. goto_middle_file (panel);
  2871. break;
  2872. case CK_TopOnScreen:
  2873. goto_top_file (panel);
  2874. break;
  2875. case CK_Mark:
  2876. mark_file (panel);
  2877. break;
  2878. case CK_MarkUp:
  2879. mark_file_up (panel);
  2880. break;
  2881. case CK_MarkDown:
  2882. mark_file_down (panel);
  2883. break;
  2884. case CK_MarkLeft:
  2885. mark_file_left (panel);
  2886. break;
  2887. case CK_MarkRight:
  2888. mark_file_right (panel);
  2889. break;
  2890. case CK_CdParentSmart:
  2891. res = force_maybe_cd ();
  2892. break;
  2893. case CK_Up:
  2894. move_up (panel);
  2895. break;
  2896. case CK_Down:
  2897. move_down (panel);
  2898. break;
  2899. case CK_Left:
  2900. res = move_left (panel);
  2901. break;
  2902. case CK_Right:
  2903. res = move_right (panel);
  2904. break;
  2905. case CK_Bottom:
  2906. move_end (panel);
  2907. break;
  2908. case CK_Top:
  2909. move_home (panel);
  2910. break;
  2911. #ifdef HAVE_CHARSET
  2912. case CK_SelectCodepage:
  2913. panel_change_encoding (panel);
  2914. break;
  2915. #endif
  2916. case CK_ScrollLeft:
  2917. panel_content_scroll_left (panel);
  2918. break;
  2919. case CK_ScrollRight:
  2920. panel_content_scroll_right (panel);
  2921. break;
  2922. case CK_Search:
  2923. start_search (panel);
  2924. break;
  2925. case CK_SearchStop:
  2926. break;
  2927. case CK_PanelOtherSync:
  2928. panel_sync_other (panel);
  2929. break;
  2930. case CK_Sort:
  2931. panel_select_sort_order (panel);
  2932. break;
  2933. case CK_SortPrev:
  2934. panel_toggle_sort_order_prev (panel);
  2935. break;
  2936. case CK_SortNext:
  2937. panel_toggle_sort_order_next (panel);
  2938. break;
  2939. case CK_SortReverse:
  2940. panel->sort_info.reverse = !panel->sort_info.reverse;
  2941. panel_set_sort_order (panel, panel->sort_field);
  2942. break;
  2943. case CK_SortByName:
  2944. panel_set_sort_type_by_id (panel, "name");
  2945. break;
  2946. case CK_SortByExt:
  2947. panel_set_sort_type_by_id (panel, "extension");
  2948. break;
  2949. case CK_SortBySize:
  2950. panel_set_sort_type_by_id (panel, "size");
  2951. break;
  2952. case CK_SortByMTime:
  2953. panel_set_sort_type_by_id (panel, "mtime");
  2954. break;
  2955. default:
  2956. res = MSG_NOT_HANDLED;
  2957. break;
  2958. }
  2959. return res;
  2960. }
  2961. /* --------------------------------------------------------------------------------------------- */
  2962. static cb_ret_t
  2963. panel_key (WPanel * panel, int key)
  2964. {
  2965. size_t i;
  2966. if (is_abort_char (key))
  2967. {
  2968. stop_search (panel);
  2969. return MSG_HANDLED;
  2970. }
  2971. if (panel->searching && ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE))
  2972. {
  2973. do_search (panel, key);
  2974. return MSG_HANDLED;
  2975. }
  2976. for (i = 0; panel_map[i].key != 0; i++)
  2977. if (key == panel_map[i].key)
  2978. return panel_execute_cmd (panel, panel_map[i].command);
  2979. if (panels_options.torben_fj_mode && key == ALT ('h'))
  2980. {
  2981. goto_middle_file (panel);
  2982. return MSG_HANDLED;
  2983. }
  2984. if (!command_prompt && ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE))
  2985. {
  2986. start_search (panel);
  2987. do_search (panel, key);
  2988. return MSG_HANDLED;
  2989. }
  2990. return MSG_NOT_HANDLED;
  2991. }
  2992. /* --------------------------------------------------------------------------------------------- */
  2993. static cb_ret_t
  2994. panel_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
  2995. {
  2996. WPanel *panel = PANEL (w);
  2997. WButtonBar *bb;
  2998. switch (msg)
  2999. {
  3000. case MSG_INIT:
  3001. /* subscribe to "history_load" event */
  3002. mc_event_add (w->owner->event_group, MCEVENT_HISTORY_LOAD, panel_load_history, w, NULL);
  3003. /* subscribe to "history_save" event */
  3004. mc_event_add (w->owner->event_group, MCEVENT_HISTORY_SAVE, panel_save_history, w, NULL);
  3005. return MSG_HANDLED;
  3006. case MSG_DRAW:
  3007. /* Repaint everything, including frame and separator */
  3008. widget_erase (w);
  3009. show_dir (panel);
  3010. panel_print_header (panel);
  3011. adjust_top_file (panel);
  3012. paint_dir (panel);
  3013. mini_info_separator (panel);
  3014. display_mini_info (panel);
  3015. panel->dirty = 0;
  3016. return MSG_HANDLED;
  3017. case MSG_FOCUS:
  3018. state_mark = -1;
  3019. current_panel = panel;
  3020. panel->active = 1;
  3021. if (mc_chdir (panel->cwd_vpath) != 0)
  3022. {
  3023. char *cwd;
  3024. cwd = vfs_path_to_str_flags (panel->cwd_vpath, 0, VPF_STRIP_PASSWORD);
  3025. message (D_ERROR, MSG_ERROR, _("Cannot chdir to \"%s\"\n%s"),
  3026. cwd, unix_error_string (errno));
  3027. g_free (cwd);
  3028. }
  3029. else
  3030. subshell_chdir (panel->cwd_vpath);
  3031. update_xterm_title_path ();
  3032. select_item (panel);
  3033. bb = find_buttonbar (w->owner);
  3034. midnight_set_buttonbar (bb);
  3035. widget_redraw (WIDGET (bb));
  3036. return MSG_HANDLED;
  3037. case MSG_UNFOCUS:
  3038. /* Janne: look at this for the multiple panel options */
  3039. stop_search (panel);
  3040. panel->active = 0;
  3041. unselect_item (panel);
  3042. return MSG_HANDLED;
  3043. case MSG_KEY:
  3044. return panel_key (panel, parm);
  3045. case MSG_ACTION:
  3046. return panel_execute_cmd (panel, parm);
  3047. case MSG_DESTROY:
  3048. /* unsubscribe from "history_load" event */
  3049. mc_event_del (w->owner->event_group, MCEVENT_HISTORY_LOAD, panel_load_history, w);
  3050. /* unsubscribe from "history_save" event */
  3051. mc_event_del (w->owner->event_group, MCEVENT_HISTORY_SAVE, panel_save_history, w);
  3052. panel_destroy (panel);
  3053. free_my_statfs ();
  3054. return MSG_HANDLED;
  3055. default:
  3056. return widget_default_callback (w, sender, msg, parm, data);
  3057. }
  3058. }
  3059. /* --------------------------------------------------------------------------------------------- */
  3060. /* */
  3061. /* Panel mouse events support routines */
  3062. /* */
  3063. static void
  3064. mouse_toggle_mark (WPanel * panel)
  3065. {
  3066. do_mark_file (panel, MARK_DONT_MOVE);
  3067. mouse_marking = selection (panel)->f.marked;
  3068. mouse_mark_panel = current_panel;
  3069. }
  3070. /* --------------------------------------------------------------------------------------------- */
  3071. static void
  3072. mouse_set_mark (WPanel * panel)
  3073. {
  3074. if (mouse_mark_panel == panel)
  3075. {
  3076. if (mouse_marking && !(selection (panel)->f.marked))
  3077. do_mark_file (panel, MARK_DONT_MOVE);
  3078. else if (!mouse_marking && (selection (panel)->f.marked))
  3079. do_mark_file (panel, MARK_DONT_MOVE);
  3080. }
  3081. }
  3082. /* --------------------------------------------------------------------------------------------- */
  3083. static gboolean
  3084. mark_if_marking (WPanel * panel, const mouse_event_t * event)
  3085. {
  3086. if ((event->buttons & GPM_B_RIGHT) != 0)
  3087. {
  3088. if (event->msg == MSG_MOUSE_DOWN)
  3089. mouse_toggle_mark (panel);
  3090. else
  3091. mouse_set_mark (panel);
  3092. return TRUE;
  3093. }
  3094. return FALSE;
  3095. }
  3096. /* --------------------------------------------------------------------------------------------- */
  3097. /** Determine which column was clicked, and sort the panel on
  3098. * that column, or reverse sort on that column if already
  3099. * sorted on that column.
  3100. */
  3101. static void
  3102. mouse_sort_col (WPanel * panel, int x)
  3103. {
  3104. int i;
  3105. const char *lc_sort_name = NULL;
  3106. panel_field_t *col_sort_format = NULL;
  3107. format_e *format;
  3108. for (i = 0, format = panel->format; format != NULL; format = format->next)
  3109. {
  3110. i += format->field_len;
  3111. if (x < i + 1)
  3112. {
  3113. /* found column */
  3114. lc_sort_name = format->title;
  3115. break;
  3116. }
  3117. }
  3118. if (lc_sort_name == NULL)
  3119. return;
  3120. for (i = 0; panel_fields[i].id != NULL; i++)
  3121. {
  3122. const char *title;
  3123. title = panel_get_title_without_hotkey (panel_fields[i].title_hotkey);
  3124. if (strcmp (title, lc_sort_name) == 0 && panel_fields[i].sort_routine != NULL)
  3125. {
  3126. col_sort_format = &panel_fields[i];
  3127. break;
  3128. }
  3129. }
  3130. if (col_sort_format == NULL)
  3131. return;
  3132. if (panel->sort_field == col_sort_format)
  3133. {
  3134. /* reverse the sort if clicked column is already the sorted column */
  3135. panel->sort_info.reverse = !panel->sort_info.reverse;
  3136. }
  3137. else
  3138. {
  3139. /* new sort is forced to be ascending */
  3140. panel->sort_info.reverse = FALSE;
  3141. }
  3142. panel_set_sort_order (panel, col_sort_format);
  3143. }
  3144. /* --------------------------------------------------------------------------------------------- */
  3145. static void
  3146. panel_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
  3147. {
  3148. WPanel *panel = PANEL (w);
  3149. gboolean is_active;
  3150. is_active = widget_is_active (w);
  3151. switch (msg)
  3152. {
  3153. case MSG_MOUSE_DOWN:
  3154. if (event->y == 0)
  3155. {
  3156. /* top frame */
  3157. if (event->x == 1)
  3158. /* "<" button */
  3159. directory_history_prev (panel);
  3160. else if (event->x == w->cols - 2)
  3161. /* ">" button */
  3162. directory_history_next (panel);
  3163. else if (event->x >= w->cols - 5 && event->x <= w->cols - 3)
  3164. /* "^" button */
  3165. directory_history_list (panel);
  3166. else if (event->x == w->cols - 6)
  3167. /* "." button show/hide hidden files */
  3168. send_message (midnight_dlg, NULL, MSG_ACTION, CK_ShowHidden, NULL);
  3169. else
  3170. {
  3171. /* no other events on 1st line, return MOU_UNHANDLED */
  3172. event->result.abort = TRUE;
  3173. /* avoid extra panel redraw */
  3174. panel->dirty = 0;
  3175. }
  3176. break;
  3177. }
  3178. if (event->y == 1)
  3179. {
  3180. /* sort on clicked column */
  3181. mouse_sort_col (panel, event->x + 1);
  3182. break;
  3183. }
  3184. if (!is_active)
  3185. change_panel ();
  3186. MC_FALLTHROUGH;
  3187. case MSG_MOUSE_DRAG:
  3188. {
  3189. int y, last, my_index;
  3190. last = panel->dir.len - 1;
  3191. y = event->y - 2;
  3192. if (panel->top_file + y > last)
  3193. my_index = last;
  3194. else
  3195. {
  3196. my_index = panel->top_file + y;
  3197. if (panel->list_cols > 1)
  3198. {
  3199. int width, lines;
  3200. width = (w->cols - 2) / panel->list_cols;
  3201. lines = panel_lines (panel);
  3202. my_index += lines * (event->x / width);
  3203. }
  3204. if (my_index > last)
  3205. my_index = last;
  3206. }
  3207. if (my_index != panel->selected)
  3208. {
  3209. unselect_item (panel);
  3210. panel->selected = my_index;
  3211. select_item (panel);
  3212. }
  3213. /* This one is new */
  3214. mark_if_marking (panel, event);
  3215. }
  3216. break;
  3217. case MSG_MOUSE_UP:
  3218. break;
  3219. case MSG_MOUSE_CLICK:
  3220. if ((event->count & GPM_DOUBLE) != 0)
  3221. {
  3222. int y, lines;
  3223. y = event->y - 2;
  3224. lines = panel_lines (panel);
  3225. if (y >= 0 && y < lines)
  3226. do_enter (panel);
  3227. }
  3228. break;
  3229. case MSG_MOUSE_MOVE:
  3230. break;
  3231. case MSG_MOUSE_SCROLL_UP:
  3232. if (is_active)
  3233. {
  3234. if (panels_options.mouse_move_pages && panel->top_file > 0)
  3235. prev_page (panel);
  3236. else /* We are in first page */
  3237. move_up (panel);
  3238. }
  3239. break;
  3240. case MSG_MOUSE_SCROLL_DOWN:
  3241. if (is_active)
  3242. {
  3243. if (panels_options.mouse_move_pages
  3244. && panel->top_file + panel_items (panel) < panel->dir.len)
  3245. next_page (panel);
  3246. else /* We are in last page */
  3247. move_down (panel);
  3248. }
  3249. break;
  3250. default:
  3251. break;
  3252. }
  3253. if (panel->dirty)
  3254. widget_redraw (w);
  3255. }
  3256. /* --------------------------------------------------------------------------------------------- */
  3257. static void
  3258. reload_panelized (WPanel * panel)
  3259. {
  3260. int i, j;
  3261. dir_list *list = &panel->dir;
  3262. /* refresh current VFS directory required for vfs_path_from_str() */
  3263. (void) mc_chdir (panel->cwd_vpath);
  3264. for (i = 0, j = 0; i < list->len; i++)
  3265. {
  3266. vfs_path_t *vpath;
  3267. vpath = vfs_path_from_str (list->list[i].fname);
  3268. if (mc_lstat (vpath, &list->list[i].st) != 0)
  3269. g_free (list->list[i].fname);
  3270. else
  3271. {
  3272. if (j != i)
  3273. list->list[j] = list->list[i];
  3274. j++;
  3275. }
  3276. vfs_path_free (vpath);
  3277. }
  3278. if (j == 0)
  3279. dir_list_init (list);
  3280. else
  3281. list->len = j;
  3282. recalculate_panel_summary (panel);
  3283. if (panel != current_panel)
  3284. (void) mc_chdir (current_panel->cwd_vpath);
  3285. }
  3286. /* --------------------------------------------------------------------------------------------- */
  3287. static void
  3288. update_one_panel_widget (WPanel * panel, panel_update_flags_t flags, const char *current_file)
  3289. {
  3290. gboolean free_pointer;
  3291. char *my_current_file = NULL;
  3292. if ((flags & UP_RELOAD) != 0)
  3293. {
  3294. panel->is_panelized = FALSE;
  3295. mc_setctl (panel->cwd_vpath, VFS_SETCTL_FLUSH, 0);
  3296. memset (&(panel->dir_stat), 0, sizeof (panel->dir_stat));
  3297. }
  3298. /* If current_file == -1 (an invalid pointer) then preserve selection */
  3299. free_pointer = current_file == UP_KEEPSEL;
  3300. if (free_pointer)
  3301. {
  3302. my_current_file = g_strdup (panel->dir.list[panel->selected].fname);
  3303. current_file = my_current_file;
  3304. }
  3305. if (panel->is_panelized)
  3306. reload_panelized (panel);
  3307. else
  3308. panel_reload (panel);
  3309. try_to_select (panel, current_file);
  3310. panel->dirty = 1;
  3311. if (free_pointer)
  3312. g_free (my_current_file);
  3313. }
  3314. /* --------------------------------------------------------------------------------------------- */
  3315. static void
  3316. update_one_panel (int which, panel_update_flags_t flags, const char *current_file)
  3317. {
  3318. if (get_display_type (which) == view_listing)
  3319. {
  3320. WPanel *panel;
  3321. panel = PANEL (get_panel_widget (which));
  3322. if (panel->is_panelized)
  3323. flags &= ~UP_RELOAD;
  3324. update_one_panel_widget (panel, flags, current_file);
  3325. }
  3326. }
  3327. /* --------------------------------------------------------------------------------------------- */
  3328. static void
  3329. do_select (WPanel * panel, int i)
  3330. {
  3331. if (i != panel->selected)
  3332. {
  3333. panel->dirty = 1;
  3334. panel->selected = i;
  3335. panel->top_file = panel->selected - (WIDGET (panel)->lines - 2) / 2;
  3336. if (panel->top_file < 0)
  3337. panel->top_file = 0;
  3338. }
  3339. }
  3340. /* --------------------------------------------------------------------------------------------- */
  3341. static void
  3342. do_try_to_select (WPanel * panel, const char *name)
  3343. {
  3344. int i;
  3345. char *subdir;
  3346. if (!name)
  3347. {
  3348. do_select (panel, 0);
  3349. return;
  3350. }
  3351. /* We only want the last component of the directory,
  3352. * and from this only the name without suffix.
  3353. * Cut prefix if the panel is not panelized */
  3354. if (panel->is_panelized)
  3355. subdir = vfs_strip_suffix_from_filename (name);
  3356. else
  3357. subdir = vfs_strip_suffix_from_filename (x_basename (name));
  3358. /* Search that subdir or filename without prefix (if not panelized panel), select it if found */
  3359. for (i = 0; i < panel->dir.len; i++)
  3360. {
  3361. if (strcmp (subdir, panel->dir.list[i].fname) == 0)
  3362. {
  3363. do_select (panel, i);
  3364. g_free (subdir);
  3365. return;
  3366. }
  3367. }
  3368. /* Try to select a file near the file that is missing */
  3369. if (panel->selected >= panel->dir.len)
  3370. do_select (panel, panel->dir.len - 1);
  3371. g_free (subdir);
  3372. }
  3373. /* --------------------------------------------------------------------------------------------- */
  3374. /* event callback */
  3375. static gboolean
  3376. event_update_panels (const gchar * event_group_name, const gchar * event_name,
  3377. gpointer init_data, gpointer data)
  3378. {
  3379. (void) event_group_name;
  3380. (void) event_name;
  3381. (void) init_data;
  3382. (void) data;
  3383. update_panels (UP_RELOAD, UP_KEEPSEL);
  3384. return TRUE;
  3385. }
  3386. /* --------------------------------------------------------------------------------------------- */
  3387. /* event callback */
  3388. static gboolean
  3389. panel_save_current_file_to_clip_file (const gchar * event_group_name, const gchar * event_name,
  3390. gpointer init_data, gpointer data)
  3391. {
  3392. (void) event_group_name;
  3393. (void) event_name;
  3394. (void) init_data;
  3395. (void) data;
  3396. if (current_panel->marked == 0)
  3397. mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_text_to_file",
  3398. (gpointer) selection (current_panel)->fname);
  3399. else
  3400. {
  3401. int i;
  3402. gboolean first = TRUE;
  3403. char *flist = NULL;
  3404. for (i = 0; i < current_panel->dir.len; i++)
  3405. if (current_panel->dir.list[i].f.marked != 0)
  3406. { /* Skip the unmarked ones */
  3407. if (first)
  3408. {
  3409. flist = g_strdup (current_panel->dir.list[i].fname);
  3410. first = FALSE;
  3411. }
  3412. else
  3413. {
  3414. /* Add empty lines after the file */
  3415. char *tmp;
  3416. tmp =
  3417. g_strconcat (flist, "\n", current_panel->dir.list[i].fname, (char *) NULL);
  3418. g_free (flist);
  3419. flist = tmp;
  3420. }
  3421. }
  3422. mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_text_to_file", (gpointer) flist);
  3423. g_free (flist);
  3424. }
  3425. return TRUE;
  3426. }
  3427. /* --------------------------------------------------------------------------------------------- */
  3428. static vfs_path_t *
  3429. panel_recursive_cd_to_parent (const vfs_path_t * vpath)
  3430. {
  3431. vfs_path_t *cwd_vpath;
  3432. cwd_vpath = vfs_path_clone (vpath);
  3433. while (mc_chdir (cwd_vpath) < 0)
  3434. {
  3435. const char *panel_cwd_path;
  3436. vfs_path_t *tmp_vpath;
  3437. /* check if path contains only '/' */
  3438. panel_cwd_path = vfs_path_as_str (cwd_vpath);
  3439. if (panel_cwd_path != NULL && IS_PATH_SEP (panel_cwd_path[0]) && panel_cwd_path[1] == '\0')
  3440. return NULL;
  3441. tmp_vpath = vfs_path_vtokens_get (cwd_vpath, 0, -1);
  3442. vfs_path_free (cwd_vpath);
  3443. cwd_vpath =
  3444. vfs_path_build_filename (PATH_SEP_STR, vfs_path_as_str (tmp_vpath), (char *) NULL);
  3445. vfs_path_free (tmp_vpath);
  3446. }
  3447. return cwd_vpath;
  3448. }
  3449. /* --------------------------------------------------------------------------------------------- */
  3450. /*** public functions ****************************************************************************/
  3451. /* --------------------------------------------------------------------------------------------- */
  3452. void
  3453. try_to_select (WPanel * panel, const char *name)
  3454. {
  3455. do_try_to_select (panel, name);
  3456. select_item (panel);
  3457. }
  3458. /* --------------------------------------------------------------------------------------------- */
  3459. void
  3460. panel_clean_dir (WPanel * panel)
  3461. {
  3462. panel->top_file = 0;
  3463. panel->selected = 0;
  3464. panel->marked = 0;
  3465. panel->dirs_marked = 0;
  3466. panel->total = 0;
  3467. panel->searching = FALSE;
  3468. panel->is_panelized = FALSE;
  3469. panel->dirty = 1;
  3470. panel->content_shift = -1;
  3471. panel->max_shift = -1;
  3472. dir_list_clean (&panel->dir);
  3473. }
  3474. /* --------------------------------------------------------------------------------------------- */
  3475. /**
  3476. * Set Up panel's current dir object
  3477. *
  3478. * @param panel panel object
  3479. * @param path_str string contain path
  3480. */
  3481. void
  3482. panel_set_cwd (WPanel * panel, const vfs_path_t * vpath)
  3483. {
  3484. if (vpath != panel->cwd_vpath) /* check if new vpath is not the panel->cwd_vpath object */
  3485. {
  3486. vfs_path_free (panel->cwd_vpath);
  3487. panel->cwd_vpath = vfs_path_clone (vpath);
  3488. }
  3489. }
  3490. /* --------------------------------------------------------------------------------------------- */
  3491. /**
  3492. * Set Up panel's last working dir object
  3493. *
  3494. * @param panel panel object
  3495. * @param path_str string contain path
  3496. */
  3497. void
  3498. panel_set_lwd (WPanel * panel, const vfs_path_t * vpath)
  3499. {
  3500. if (vpath != panel->lwd_vpath) /* check if new vpath is not the panel->lwd_vpath object */
  3501. {
  3502. vfs_path_free (panel->lwd_vpath);
  3503. panel->lwd_vpath = vfs_path_clone (vpath);
  3504. }
  3505. }
  3506. /* --------------------------------------------------------------------------------------------- */
  3507. /**
  3508. * Panel creation for specified directory.
  3509. *
  3510. * @param panel_name specifies the name of the panel for setup retieving
  3511. * @param wpath the path of working panel directory. If path is NULL then panel will be created
  3512. * for current directory
  3513. *
  3514. * @return new instance of WPanel
  3515. */
  3516. WPanel *
  3517. panel_new_with_dir (const char *panel_name, const vfs_path_t * vpath)
  3518. {
  3519. WPanel *panel;
  3520. Widget *w;
  3521. char *section;
  3522. int i, err;
  3523. char *curdir = NULL;
  3524. panel = g_new0 (WPanel, 1);
  3525. w = WIDGET (panel);
  3526. /* No know sizes of the panel at startup */
  3527. widget_init (w, 0, 0, 0, 0, panel_callback, panel_mouse_callback);
  3528. w->options |= WOP_SELECTABLE | WOP_TOP_SELECT;
  3529. if (vpath != NULL)
  3530. {
  3531. curdir = _vfs_get_cwd ();
  3532. panel_set_cwd (panel, vpath);
  3533. }
  3534. else
  3535. {
  3536. vfs_setup_cwd ();
  3537. panel->cwd_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
  3538. }
  3539. panel_set_lwd (panel, vfs_get_raw_current_dir ());
  3540. panel->hist_name = g_strconcat ("Dir Hist ", panel_name, (char *) NULL);
  3541. /* directories history will be get later */
  3542. panel->dir.size = DIR_LIST_MIN_SIZE;
  3543. panel->dir.list = g_new (file_entry_t, panel->dir.size);
  3544. panel->dir.len = 0;
  3545. panel->active = 0;
  3546. panel->filter = NULL;
  3547. panel->list_cols = 1;
  3548. panel->brief_cols = 2;
  3549. panel->top_file = 0;
  3550. panel->selected = 0;
  3551. panel->marked = 0;
  3552. panel->total = 0;
  3553. panel->dirty = 1;
  3554. panel->searching = FALSE;
  3555. panel->dirs_marked = 0;
  3556. panel->is_panelized = FALSE;
  3557. panel->format = NULL;
  3558. panel->status_format = NULL;
  3559. panel->format_modified = 1;
  3560. panel->content_shift = -1;
  3561. panel->max_shift = -1;
  3562. panel->panel_name = g_strdup (panel_name);
  3563. panel->user_format = g_strdup (DEFAULT_USER_FORMAT);
  3564. #ifdef HAVE_CHARSET
  3565. panel->codepage = SELECT_CHARSET_NO_TRANSLATE;
  3566. #endif
  3567. for (i = 0; i < LIST_FORMATS; i++)
  3568. panel->user_status_format[i] = g_strdup (DEFAULT_USER_FORMAT);
  3569. panel->search_buffer[0] = '\0';
  3570. panel->prev_search_buffer[0] = '\0';
  3571. panel->frame_size = frame_half;
  3572. section = g_strconcat ("Temporal:", panel->panel_name, (char *) NULL);
  3573. if (!mc_config_has_group (mc_global.main_config, section))
  3574. {
  3575. g_free (section);
  3576. section = g_strdup (panel->panel_name);
  3577. }
  3578. panel_load_setup (panel, section);
  3579. g_free (section);
  3580. /* Load format strings */
  3581. err = set_panel_formats (panel);
  3582. if (err != 0)
  3583. set_panel_formats (panel);
  3584. #ifdef HAVE_CHARSET
  3585. {
  3586. const vfs_path_element_t *path_element;
  3587. path_element = vfs_path_get_by_index (panel->cwd_vpath, -1);
  3588. if (path_element->encoding != NULL)
  3589. panel->codepage = get_codepage_index (path_element->encoding);
  3590. }
  3591. #endif
  3592. if (mc_chdir (panel->cwd_vpath) != 0)
  3593. {
  3594. #ifdef HAVE_CHARSET
  3595. panel->codepage = SELECT_CHARSET_NO_TRANSLATE;
  3596. #endif
  3597. vfs_setup_cwd ();
  3598. vfs_path_free (panel->cwd_vpath);
  3599. panel->cwd_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
  3600. }
  3601. /* Load the default format */
  3602. dir_list_load (&panel->dir, panel->cwd_vpath, panel->sort_field->sort_routine,
  3603. &panel->sort_info, panel->filter);
  3604. /* Restore old right path */
  3605. if (curdir != NULL)
  3606. {
  3607. vfs_path_t *tmp_vpath;
  3608. tmp_vpath = vfs_path_from_str (curdir);
  3609. err = mc_chdir (tmp_vpath);
  3610. vfs_path_free (tmp_vpath);
  3611. }
  3612. g_free (curdir);
  3613. return panel;
  3614. }
  3615. /* --------------------------------------------------------------------------------------------- */
  3616. void
  3617. panel_reload (WPanel * panel)
  3618. {
  3619. struct stat current_stat;
  3620. vfs_path_t *cwd_vpath;
  3621. if (panels_options.fast_reload && stat (vfs_path_as_str (panel->cwd_vpath), &current_stat) == 0
  3622. && current_stat.st_ctime == panel->dir_stat.st_ctime
  3623. && current_stat.st_mtime == panel->dir_stat.st_mtime)
  3624. return;
  3625. cwd_vpath = panel_recursive_cd_to_parent (panel->cwd_vpath);
  3626. vfs_path_free (panel->cwd_vpath);
  3627. if (cwd_vpath == NULL)
  3628. {
  3629. panel->cwd_vpath = vfs_path_from_str (PATH_SEP_STR);
  3630. panel_clean_dir (panel);
  3631. dir_list_init (&panel->dir);
  3632. return;
  3633. }
  3634. panel->cwd_vpath = cwd_vpath;
  3635. memset (&(panel->dir_stat), 0, sizeof (panel->dir_stat));
  3636. show_dir (panel);
  3637. dir_list_reload (&panel->dir, panel->cwd_vpath, panel->sort_field->sort_routine,
  3638. &panel->sort_info, panel->filter);
  3639. panel->dirty = 1;
  3640. if (panel->selected >= panel->dir.len)
  3641. do_select (panel, panel->dir.len - 1);
  3642. recalculate_panel_summary (panel);
  3643. }
  3644. /* --------------------------------------------------------------------------------------------- */
  3645. /* Switches the panel to the mode specified in the format */
  3646. /* Seting up both format and status string. Return: 0 - on success; */
  3647. /* 1 - format error; 2 - status error; 3 - errors in both formats. */
  3648. int
  3649. set_panel_formats (WPanel * p)
  3650. {
  3651. format_e *form;
  3652. char *err = NULL;
  3653. int retcode = 0;
  3654. form = use_display_format (p, panel_format (p), &err, FALSE);
  3655. if (err != NULL)
  3656. {
  3657. g_free (err);
  3658. retcode = 1;
  3659. }
  3660. else
  3661. {
  3662. delete_format (p->format);
  3663. p->format = form;
  3664. }
  3665. if (panels_options.show_mini_info)
  3666. {
  3667. form = use_display_format (p, mini_status_format (p), &err, TRUE);
  3668. if (err != NULL)
  3669. {
  3670. g_free (err);
  3671. retcode += 2;
  3672. }
  3673. else
  3674. {
  3675. delete_format (p->status_format);
  3676. p->status_format = form;
  3677. }
  3678. }
  3679. panel_format_modified (p);
  3680. panel_update_cols (WIDGET (p), p->frame_size);
  3681. if (retcode)
  3682. message (D_ERROR, _("Warning"),
  3683. _("User supplied format looks invalid, reverting to default."));
  3684. if (retcode & 0x01)
  3685. {
  3686. g_free (p->user_format);
  3687. p->user_format = g_strdup (DEFAULT_USER_FORMAT);
  3688. }
  3689. if (retcode & 0x02)
  3690. {
  3691. g_free (p->user_status_format[p->list_format]);
  3692. p->user_status_format[p->list_format] = g_strdup (DEFAULT_USER_FORMAT);
  3693. }
  3694. return retcode;
  3695. }
  3696. /* --------------------------------------------------------------------------------------------- */
  3697. /* Select current item and readjust the panel */
  3698. void
  3699. select_item (WPanel * panel)
  3700. {
  3701. adjust_top_file (panel);
  3702. panel->dirty = 1;
  3703. execute_hooks (select_file_hook);
  3704. }
  3705. /* --------------------------------------------------------------------------------------------- */
  3706. /** Clears all files in the panel, used only when one file was marked */
  3707. void
  3708. unmark_files (WPanel * panel)
  3709. {
  3710. int i;
  3711. if (!panel->marked)
  3712. return;
  3713. for (i = 0; i < panel->dir.len; i++)
  3714. file_mark (panel, i, 0);
  3715. panel->dirs_marked = 0;
  3716. panel->marked = 0;
  3717. panel->total = 0;
  3718. }
  3719. /* --------------------------------------------------------------------------------------------- */
  3720. /** Recalculate the panels summary information, used e.g. when marked
  3721. files might have been removed by an external command */
  3722. void
  3723. recalculate_panel_summary (WPanel * panel)
  3724. {
  3725. int i;
  3726. panel->marked = 0;
  3727. panel->dirs_marked = 0;
  3728. panel->total = 0;
  3729. for (i = 0; i < panel->dir.len; i++)
  3730. if (panel->dir.list[i].f.marked)
  3731. {
  3732. /* do_file_mark will return immediately if newmark == oldmark.
  3733. So we have to first unmark it to get panel's summary information
  3734. updated. (Norbert) */
  3735. panel->dir.list[i].f.marked = 0;
  3736. do_file_mark (panel, i, 1);
  3737. }
  3738. }
  3739. /* --------------------------------------------------------------------------------------------- */
  3740. /** This routine marks a file or a directory */
  3741. void
  3742. do_file_mark (WPanel * panel, int idx, int mark)
  3743. {
  3744. if (panel->dir.list[idx].f.marked == mark)
  3745. return;
  3746. /* Only '..' can't be marked, '.' isn't visible */
  3747. if (DIR_IS_DOTDOT (panel->dir.list[idx].fname))
  3748. return;
  3749. file_mark (panel, idx, mark);
  3750. if (panel->dir.list[idx].f.marked)
  3751. {
  3752. panel->marked++;
  3753. if (S_ISDIR (panel->dir.list[idx].st.st_mode))
  3754. {
  3755. if (panel->dir.list[idx].f.dir_size_computed)
  3756. panel->total += (uintmax_t) panel->dir.list[idx].st.st_size;
  3757. panel->dirs_marked++;
  3758. }
  3759. else
  3760. panel->total += (uintmax_t) panel->dir.list[idx].st.st_size;
  3761. set_colors (panel);
  3762. }
  3763. else
  3764. {
  3765. if (S_ISDIR (panel->dir.list[idx].st.st_mode))
  3766. {
  3767. if (panel->dir.list[idx].f.dir_size_computed)
  3768. panel->total -= (uintmax_t) panel->dir.list[idx].st.st_size;
  3769. panel->dirs_marked--;
  3770. }
  3771. else
  3772. panel->total -= (uintmax_t) panel->dir.list[idx].st.st_size;
  3773. panel->marked--;
  3774. }
  3775. }
  3776. /* --------------------------------------------------------------------------------------------- */
  3777. /**
  3778. * Changes the current directory of the panel.
  3779. * Record change in the directory history.
  3780. */
  3781. gboolean
  3782. do_panel_cd (WPanel * panel, const vfs_path_t * new_dir_vpath, enum cd_enum cd_type)
  3783. {
  3784. gboolean r;
  3785. r = _do_panel_cd (panel, new_dir_vpath, cd_type);
  3786. if (r)
  3787. directory_history_add (panel, panel->cwd_vpath);
  3788. return r;
  3789. }
  3790. /* --------------------------------------------------------------------------------------------- */
  3791. void
  3792. file_mark (WPanel * panel, int lc_index, int val)
  3793. {
  3794. if (panel->dir.list[lc_index].f.marked != val)
  3795. {
  3796. panel->dir.list[lc_index].f.marked = val;
  3797. panel->dirty = 1;
  3798. }
  3799. }
  3800. /* --------------------------------------------------------------------------------------------- */
  3801. void
  3802. panel_re_sort (WPanel * panel)
  3803. {
  3804. char *filename;
  3805. int i;
  3806. if (panel == NULL)
  3807. return;
  3808. filename = g_strdup (selection (panel)->fname);
  3809. unselect_item (panel);
  3810. dir_list_sort (&panel->dir, panel->sort_field->sort_routine, &panel->sort_info);
  3811. panel->selected = -1;
  3812. for (i = panel->dir.len; i != 0; i--)
  3813. if (strcmp (panel->dir.list[i - 1].fname, filename) == 0)
  3814. {
  3815. panel->selected = i - 1;
  3816. break;
  3817. }
  3818. g_free (filename);
  3819. panel->top_file = panel->selected - panel_items (panel) / 2;
  3820. select_item (panel);
  3821. panel->dirty = 1;
  3822. }
  3823. /* --------------------------------------------------------------------------------------------- */
  3824. void
  3825. panel_set_sort_order (WPanel * panel, const panel_field_t * sort_order)
  3826. {
  3827. if (sort_order == NULL)
  3828. return;
  3829. panel->sort_field = sort_order;
  3830. /* The directory is already sorted, we have to load the unsorted stuff */
  3831. if (sort_order->sort_routine == (GCompareFunc) unsorted)
  3832. {
  3833. char *current_file;
  3834. current_file = g_strdup (panel->dir.list[panel->selected].fname);
  3835. panel_reload (panel);
  3836. try_to_select (panel, current_file);
  3837. g_free (current_file);
  3838. }
  3839. panel_re_sort (panel);
  3840. }
  3841. /* --------------------------------------------------------------------------------------------- */
  3842. #ifdef HAVE_CHARSET
  3843. /**
  3844. * Change panel encoding.
  3845. * @param panel WPanel object
  3846. */
  3847. void
  3848. panel_change_encoding (WPanel * panel)
  3849. {
  3850. const char *encoding = NULL;
  3851. char *errmsg;
  3852. int r;
  3853. r = select_charset (-1, -1, panel->codepage, FALSE);
  3854. if (r == SELECT_CHARSET_CANCEL)
  3855. return; /* Cancel */
  3856. panel->codepage = r;
  3857. if (panel->codepage == SELECT_CHARSET_NO_TRANSLATE)
  3858. {
  3859. /* No translation */
  3860. vfs_path_t *cd_path_vpath;
  3861. g_free (init_translation_table (mc_global.display_codepage, mc_global.display_codepage));
  3862. cd_path_vpath = remove_encoding_from_path (panel->cwd_vpath);
  3863. do_panel_cd (panel, cd_path_vpath, cd_parse_command);
  3864. show_dir (panel);
  3865. vfs_path_free (cd_path_vpath);
  3866. return;
  3867. }
  3868. errmsg = init_translation_table (panel->codepage, mc_global.display_codepage);
  3869. if (errmsg != NULL)
  3870. {
  3871. message (D_ERROR, MSG_ERROR, "%s", errmsg);
  3872. g_free (errmsg);
  3873. return;
  3874. }
  3875. encoding = get_codepage_id (panel->codepage);
  3876. if (encoding != NULL)
  3877. {
  3878. vfs_path_change_encoding (panel->cwd_vpath, encoding);
  3879. if (!do_panel_cd (panel, panel->cwd_vpath, cd_parse_command))
  3880. message (D_ERROR, MSG_ERROR, _("Cannot chdir to \"%s\""),
  3881. vfs_path_as_str (panel->cwd_vpath));
  3882. }
  3883. }
  3884. /* --------------------------------------------------------------------------------------------- */
  3885. /**
  3886. * Remove encode info from last path element.
  3887. *
  3888. */
  3889. vfs_path_t *
  3890. remove_encoding_from_path (const vfs_path_t * vpath)
  3891. {
  3892. vfs_path_t *ret_vpath;
  3893. GString *tmp_conv;
  3894. int indx;
  3895. ret_vpath = vfs_path_new ();
  3896. tmp_conv = g_string_new ("");
  3897. for (indx = 0; indx < vfs_path_elements_count (vpath); indx++)
  3898. {
  3899. GIConv converter;
  3900. vfs_path_element_t *path_element;
  3901. path_element = vfs_path_element_clone (vfs_path_get_by_index (vpath, indx));
  3902. if (path_element->encoding == NULL)
  3903. {
  3904. vfs_path_add_element (ret_vpath, path_element);
  3905. continue;
  3906. }
  3907. converter = str_crt_conv_to (path_element->encoding);
  3908. if (converter == INVALID_CONV)
  3909. {
  3910. vfs_path_add_element (ret_vpath, path_element);
  3911. continue;
  3912. }
  3913. MC_PTR_FREE (path_element->encoding);
  3914. str_vfs_convert_from (converter, path_element->path, tmp_conv);
  3915. g_free (path_element->path);
  3916. path_element->path = g_strndup (tmp_conv->str, tmp_conv->len);
  3917. g_string_set_size (tmp_conv, 0);
  3918. str_close_conv (converter);
  3919. str_close_conv (path_element->dir.converter);
  3920. path_element->dir.converter = INVALID_CONV;
  3921. vfs_path_add_element (ret_vpath, path_element);
  3922. }
  3923. g_string_free (tmp_conv, TRUE);
  3924. return ret_vpath;
  3925. }
  3926. #endif /* HAVE_CHARSET */
  3927. /* --------------------------------------------------------------------------------------------- */
  3928. /**
  3929. * This routine reloads the directory in both panels. It tries to
  3930. * select current_file in current_panel and other_file in other_panel.
  3931. * If current_file == -1 then it automatically sets current_file and
  3932. * other_file to the currently selected files in the panels.
  3933. *
  3934. * If flags has the UP_ONLY_CURRENT bit toggled on, then it
  3935. * will not reload the other panel.
  3936. *
  3937. * @param flags for reload panel
  3938. * @param current_file name of the current file
  3939. */
  3940. void
  3941. update_panels (panel_update_flags_t flags, const char *current_file)
  3942. {
  3943. WPanel *panel;
  3944. /* first, update other panel... */
  3945. if ((flags & UP_ONLY_CURRENT) == 0)
  3946. update_one_panel (get_other_index (), flags, UP_KEEPSEL);
  3947. /* ...then current one */
  3948. update_one_panel (get_current_index (), flags, current_file);
  3949. if (get_current_type () == view_listing)
  3950. panel = PANEL (get_panel_widget (get_current_index ()));
  3951. else
  3952. panel = PANEL (get_panel_widget (get_other_index ()));
  3953. if (!panel->is_panelized)
  3954. (void) mc_chdir (panel->cwd_vpath);
  3955. }
  3956. /* --------------------------------------------------------------------------------------------- */
  3957. gsize
  3958. panel_get_num_of_sortable_fields (void)
  3959. {
  3960. gsize ret = 0, lc_index;
  3961. for (lc_index = 0; panel_fields[lc_index].id != NULL; lc_index++)
  3962. if (panel_fields[lc_index].is_user_choice)
  3963. ret++;
  3964. return ret;
  3965. }
  3966. /* --------------------------------------------------------------------------------------------- */
  3967. char **
  3968. panel_get_sortable_fields (gsize * array_size)
  3969. {
  3970. char **ret;
  3971. gsize lc_index, i;
  3972. lc_index = panel_get_num_of_sortable_fields ();
  3973. ret = g_try_new0 (char *, lc_index + 1);
  3974. if (ret == NULL)
  3975. return NULL;
  3976. if (array_size != NULL)
  3977. *array_size = lc_index;
  3978. lc_index = 0;
  3979. for (i = 0; panel_fields[i].id != NULL; i++)
  3980. if (panel_fields[i].is_user_choice)
  3981. ret[lc_index++] = g_strdup (_(panel_fields[i].title_hotkey));
  3982. return ret;
  3983. }
  3984. /* --------------------------------------------------------------------------------------------- */
  3985. const panel_field_t *
  3986. panel_get_field_by_id (const char *name)
  3987. {
  3988. gsize lc_index;
  3989. for (lc_index = 0; panel_fields[lc_index].id != NULL; lc_index++)
  3990. if (panel_fields[lc_index].id != NULL && strcmp (name, panel_fields[lc_index].id) == 0)
  3991. return &panel_fields[lc_index];
  3992. return NULL;
  3993. }
  3994. /* --------------------------------------------------------------------------------------------- */
  3995. const panel_field_t *
  3996. panel_get_field_by_title_hotkey (const char *name)
  3997. {
  3998. gsize lc_index;
  3999. for (lc_index = 0; panel_fields[lc_index].id != NULL; lc_index++)
  4000. if (panel_fields[lc_index].title_hotkey != NULL &&
  4001. strcmp (name, _(panel_fields[lc_index].title_hotkey)) == 0)
  4002. return &panel_fields[lc_index];
  4003. return NULL;
  4004. }
  4005. /* --------------------------------------------------------------------------------------------- */
  4006. const panel_field_t *
  4007. panel_get_field_by_title (const char *name)
  4008. {
  4009. gsize lc_index;
  4010. for (lc_index = 0; panel_fields[lc_index].id != NULL; lc_index++)
  4011. {
  4012. const char *title;
  4013. title = panel_get_title_without_hotkey (panel_fields[lc_index].title_hotkey);
  4014. if (strcmp (title, name) == 0)
  4015. return &panel_fields[lc_index];
  4016. }
  4017. return NULL;
  4018. }
  4019. /* --------------------------------------------------------------------------------------------- */
  4020. gsize
  4021. panel_get_num_of_user_possible_fields (void)
  4022. {
  4023. gsize ret = 0, lc_index;
  4024. for (lc_index = 0; panel_fields[lc_index].id != NULL; lc_index++)
  4025. if (panel_fields[lc_index].use_in_user_format)
  4026. ret++;
  4027. return ret;
  4028. }
  4029. /* --------------------------------------------------------------------------------------------- */
  4030. char **
  4031. panel_get_user_possible_fields (gsize * array_size)
  4032. {
  4033. char **ret;
  4034. gsize lc_index, i;
  4035. lc_index = panel_get_num_of_user_possible_fields ();
  4036. ret = g_try_new0 (char *, lc_index + 1);
  4037. if (ret == NULL)
  4038. return NULL;
  4039. if (array_size != NULL)
  4040. *array_size = lc_index;
  4041. lc_index = 0;
  4042. for (i = 0; panel_fields[i].id != NULL; i++)
  4043. if (panel_fields[i].use_in_user_format)
  4044. ret[lc_index++] = g_strdup (_(panel_fields[i].title_hotkey));
  4045. return ret;
  4046. }
  4047. /* --------------------------------------------------------------------------------------------- */
  4048. void
  4049. panel_init (void)
  4050. {
  4051. panel_sort_up_sign = mc_skin_get ("widget-common", "sort-sign-up", "'");
  4052. panel_sort_down_sign = mc_skin_get ("widget-common", "sort-sign-down", ".");
  4053. panel_hiddenfiles_sign_show = mc_skin_get ("widget-panel", "hiddenfiles-sign-show", ".");
  4054. panel_hiddenfiles_sign_hide = mc_skin_get ("widget-panel", "hiddenfiles-sign-hide", ".");
  4055. panel_history_prev_item_sign = mc_skin_get ("widget-panel", "history-prev-item-sign", "<");
  4056. panel_history_next_item_sign = mc_skin_get ("widget-panel", "history-next-item-sign", ">");
  4057. panel_history_show_list_sign = mc_skin_get ("widget-panel", "history-show-list-sign", "^");
  4058. panel_filename_scroll_left_char =
  4059. mc_skin_get ("widget-panel", "filename-scroll-left-char", "{");
  4060. panel_filename_scroll_right_char =
  4061. mc_skin_get ("widget-panel", "filename-scroll-right-char", "}");
  4062. mc_event_add (MCEVENT_GROUP_FILEMANAGER, "update_panels", event_update_panels, NULL, NULL);
  4063. mc_event_add (MCEVENT_GROUP_FILEMANAGER, "panel_save_current_file_to_clip_file",
  4064. panel_save_current_file_to_clip_file, NULL, NULL);
  4065. }
  4066. /* --------------------------------------------------------------------------------------------- */
  4067. void
  4068. panel_deinit (void)
  4069. {
  4070. g_free (panel_sort_up_sign);
  4071. g_free (panel_sort_down_sign);
  4072. g_free (panel_hiddenfiles_sign_show);
  4073. g_free (panel_hiddenfiles_sign_hide);
  4074. g_free (panel_history_prev_item_sign);
  4075. g_free (panel_history_next_item_sign);
  4076. g_free (panel_history_show_list_sign);
  4077. g_free (panel_filename_scroll_left_char);
  4078. g_free (panel_filename_scroll_right_char);
  4079. }
  4080. /* --------------------------------------------------------------------------------------------- */
  4081. gboolean
  4082. do_cd (const vfs_path_t * new_dir_vpath, enum cd_enum exact)
  4083. {
  4084. gboolean res;
  4085. const vfs_path_t *_new_dir_vpath = new_dir_vpath;
  4086. if (current_panel->is_panelized)
  4087. {
  4088. size_t new_vpath_len;
  4089. new_vpath_len = vfs_path_len (new_dir_vpath);
  4090. if (vfs_path_equal_len (new_dir_vpath, panelized_panel.root_vpath, new_vpath_len))
  4091. _new_dir_vpath = panelized_panel.root_vpath;
  4092. }
  4093. res = do_panel_cd (current_panel, _new_dir_vpath, exact);
  4094. #ifdef HAVE_CHARSET
  4095. if (res)
  4096. {
  4097. const vfs_path_element_t *path_element;
  4098. path_element = vfs_path_get_by_index (current_panel->cwd_vpath, -1);
  4099. if (path_element->encoding != NULL)
  4100. current_panel->codepage = get_codepage_index (path_element->encoding);
  4101. else
  4102. current_panel->codepage = SELECT_CHARSET_NO_TRANSLATE;
  4103. }
  4104. #endif /* HAVE_CHARSET */
  4105. return res;
  4106. }
  4107. /* --------------------------------------------------------------------------------------------- */