| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258 |
- // $Id: Flu_File_Chooser.cpp,v 1.103 2005/03/14 15:31:45 jbryan Exp $
- /***************************************************************
- * FLU - FLTK Utility Widgets
- * Copyright (C) 2002 Ohio Supercomputer Center, Ohio State University
- *
- * This file and its content is protected by a software license.
- * You should have received a copy of this license with this file.
- * If not, please contact the Ohio Supercomputer Center immediately:
- * Attn: Jason Bryan Re: FLU 1224 Kinnear Rd, Columbus, Ohio 43212
- *
- ***************************************************************/
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <time.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #define FLU_USE_REGISTRY
- #ifdef WIN32
- #include <windows.h>
- #include <shlobj.h>
- #include <shellapi.h>
- #include <lmcons.h>
- #endif
- #if defined WIN32 && !defined CYGWIN
- #include <direct.h>
- #else
- #include <unistd.h>
- #endif
- #include <FL/Fl.H>
- #include <FL/fl_draw.H>
- #include <FL/fl_ask.H>
- #include <FL/math.h>
- #include <FL/filename.H>
- #include <FL/Fl_Pixmap.H>
- #include <FL/Fl_Scroll.H>
- #include <FL/Fl_Shared_Image.H>
- #include "FLU/flu_pixmaps.h"
- #include "FLU/Flu_Label.H"
- #include "FLU/Flu_Tree_Browser.H"
- #include "FLU/Flu_Separator.H"
- #include "FLU/Flu_Enumerations.H"
- #include "FLU/Flu_File_Chooser.H"
- #include "FLU/flu_file_chooser_pixmaps.h"
- #include "FLU/flu_pixmaps.h"
- // set default language strings
- FluSimpleString Flu_File_Chooser::favoritesTxt = "Favorites";
- #ifdef WIN32
- FluSimpleString Flu_File_Chooser::myComputerTxt = "My Computer";
- FluSimpleString Flu_File_Chooser::myDocumentsTxt = "My Documents";
- FluSimpleString Flu_File_Chooser::desktopTxt = "Desktop";
- #else
- FluSimpleString Flu_File_Chooser::myComputerTxt = "Home";
- FluSimpleString Flu_File_Chooser::myDocumentsTxt = "Temporary";
- FluSimpleString Flu_File_Chooser::desktopTxt = "Desktop";
- #endif
- FluSimpleString Flu_File_Chooser::detailTxt[4] = { "Name", "Size", "Date", "Type" };
- FluSimpleString Flu_File_Chooser::contextMenuTxt[3] = { "New Folder", "Rename", "Delete" };
- FluSimpleString Flu_File_Chooser::diskTypesTxt[6] = { "Floppy Disk", "Removable Disk",
- "Local Disk", "Compact Disk",
- "Network Disk", "RAM Disk" };
- FluSimpleString Flu_File_Chooser::filenameTxt = "Filename";
- FluSimpleString Flu_File_Chooser::okTxt = "Ok";
- FluSimpleString Flu_File_Chooser::cancelTxt = "Cancel";
- FluSimpleString Flu_File_Chooser::locationTxt = "Location";
- FluSimpleString Flu_File_Chooser::showHiddenTxt = "Show Hidden Files";
- FluSimpleString Flu_File_Chooser::fileTypesTxt = "File Types";
- FluSimpleString Flu_File_Chooser::directoryTxt = "Directory";
- FluSimpleString Flu_File_Chooser::allFilesTxt = "All Files (*)";
- FluSimpleString Flu_File_Chooser::defaultFolderNameTxt = "New Folder";
- FluSimpleString Flu_File_Chooser::backTTxt = "Go back one directory in the history";
- FluSimpleString Flu_File_Chooser::forwardTTxt = "Go forward one directory in the history";
- FluSimpleString Flu_File_Chooser::upTTxt = "Go to the parent directory";
- FluSimpleString Flu_File_Chooser::reloadTTxt = "Refresh this directory";
- FluSimpleString Flu_File_Chooser::trashTTxt = "Delete file(s)";
- FluSimpleString Flu_File_Chooser::newDirTTxt = "Create new directory";
- FluSimpleString Flu_File_Chooser::addFavoriteTTxt = "Add this directory to my favorites";
- FluSimpleString Flu_File_Chooser::previewTTxt = "Preview files";
- FluSimpleString Flu_File_Chooser::listTTxt = "View as list";
- FluSimpleString Flu_File_Chooser::wideListTTxt = "View as wide list";
- FluSimpleString Flu_File_Chooser::detailTTxt = "View details";
- FluSimpleString Flu_File_Chooser::createFolderErrTxt = "Could not create directory '%s'. You may not have permission to perform this operation.";
- FluSimpleString Flu_File_Chooser::deleteFileErrTxt = "An error ocurred while trying to delete '%s'.";
- FluSimpleString Flu_File_Chooser::fileExistsErrTxt = "File '%s' already exists!";
- FluSimpleString Flu_File_Chooser::renameErrTxt = "Unable to rename '%s' to '%s'";
- // just a string that no file could probably ever be called
- #define FAVORITES_UNIQUE_STRING "\t!@#$%^&*(Favorites)-=+"
- #define DEFAULT_ENTRY_WIDTH 235
- Fl_Pixmap up_folder_img( (char*const*)big_folder_up_xpm ),
- trash( (char*const*)trash_xpm ),
- new_folder( (char*const*)big_folder_new_xpm ),
- reload( (char*const*)reload_xpm ),
- preview_img( (char*const*)monalisa_xpm ),
- file_list_img( (char*const*)filelist_xpm ),
- file_listwide_img( (char*const*)filelistwide_xpm ),
- fileDetails( (char*const*)filedetails_xpm ),
- add_to_favorite_folder( (char*const*)folder_favorite_xpm ),
- home( (char*const*)bighome_xpm ),
- favorites( (char*const*)bigfavorites_xpm ),
- desktop( (char*const*)desktop_xpm ),
- folder_closed( (char*const*)folder_closed_xpm ),
- default_file( (char*const*)textdoc_xpm ),
- my_computer( (char*const*)my_computer_xpm ),
- computer( (char*const*)computer_xpm ),
- disk_drive( (char*const*)disk_drive_xpm ),
- cd_drive( (char*const*)cd_drive_xpm ),
- floppy_drive( (char*const*)floppy_drive_xpm ),
- removable_drive( (char*const*)removable_drive_xpm ),
- ram_drive( (char*const*)ram_drive_xpm ),
- network_drive( (char*const*)network_drive_xpm ),
- documents( (char*const*)filled_folder_xpm ),
- littlehome( (char*const*)home_xpm ),
- little_favorites( (char*const*)mini_folder_favorites_xpm ),
- little_desktop( (char*const*)mini_desktop_xpm ),
- bigdocuments( (char*const*)bigdocuments_xpm ),
- bigtemporary( (char*const*)bigtemporary_xpm );
- #define streq(a,b) (strcmp(a,b)==0)
- Flu_File_Chooser::FileTypeInfo* Flu_File_Chooser::types = NULL;
- int Flu_File_Chooser::numTypes = 0;
- int Flu_File_Chooser::typeArraySize = 0;
- Flu_File_Chooser::ContextHandlerVector Flu_File_Chooser::contextHandlers;
- Flu_File_Chooser::PreviewHandlerVector Flu_File_Chooser::previewHandlers;
- Flu_File_Chooser::ImgTxtPreview* Flu_File_Chooser::imgTxtPreview = 0;
- int (*Flu_File_Chooser::customSort)(const char*,const char*) = 0;
- FluSimpleString Flu_File_Chooser::dArrow[4];
- FluSimpleString Flu_File_Chooser::uArrow[4];
- #ifdef WIN32
- // Internationalized windows folder name access
- // Fix suggested by Fabien Costantini
- /*
- CSIDL_DESKTOPDIRECTORY -- desktop
- CSIDL_PERSONAL -- my documents
- CSIDL_PERSONAL and strip back to last "/" -> home
- */
- static FluSimpleString flu_get_special_folder( int csidl )
- {
- static char path[MAX_PATH+1];
- #ifdef FLU_USE_REGISTRY
- HKEY key;
- DWORD size = MAX_PATH;
- const char *keyQuery = "";
- switch( csidl )
- {
- case CSIDL_DESKTOPDIRECTORY: keyQuery = "Desktop"; break;
- case CSIDL_PERSONAL: keyQuery = "Personal"; break;
- }
- if( RegOpenKeyEx( HKEY_CURRENT_USER,
- "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
- 0, KEY_QUERY_VALUE, &key ) != ERROR_SUCCESS )
- return "";
- if( RegQueryValueEx( key, keyQuery, 0, 0, (LPBYTE)path, &size ) != ERROR_SUCCESS )
- return "";
- RegCloseKey( key );
- return path;
- #else
- path[0] = '\0';
- if( SUCCEEDED( SHGetSpecialFolderPath( NULL, path, csidl, FALSE ) ) )
- //if( SUCCEEDED( SHGetFolderPath( NULL, csidl, NULL, 0, path ) ) )
- {
- int len = strlen(path);
- if( len > 0 && path[len-1] != '/' && path[len-1] != '\\' )
- strcat( path, "/" );
- return path;
- }
- return "";
- #endif
- }
- #endif
- // taken explicitly from fltk/src/filename_match.cxx
- // and changed to support case-sensitive matching
- static int flu_filename_match(const char *s, const char *p)
- {
- int matched;
- for (;;) {
- switch(*p++) {
- case '?' : // match any single character
- if (!*s++) return 0;
- break;
- case '*' : // match 0-n of any characters
- if (!*p) return 1; // do trailing * quickly
- while (!flu_filename_match(s, p)) if (!*s++) return 0;
- return 1;
- case '[': { // match one character in set of form [abc-d] or [^a-b]
- if (!*s) return 0;
- int reverse = (*p=='^' || *p=='!'); if (reverse) p++;
- matched = 0;
- char last = 0;
- while (*p) {
- if (*p=='-' && last) {
- if (*s <= *++p && *s >= last ) matched = 1;
- last = 0;
- } else {
- if (*s == *p) matched = 1;
- }
- last = *p++;
- if (*p==']') break;
- }
- if (matched == reverse) return 0;
- s++; p++;}
- break;
- case '{' : // {pattern1|pattern2|pattern3}
- NEXTCASE:
- if (flu_filename_match(s,p)) return 1;
- for (matched = 0;;) {
- switch (*p++) {
- case '\\': if (*p) p++; break;
- case '{': matched++; break;
- case '}': if (!matched--) return 0; break;
- case '|': case ',': if (matched==0) goto NEXTCASE;
- case 0: return 0;
- }
- }
- case '|': // skip rest of |pattern|pattern} when called recursively
- case ',':
- for (matched = 0; *p && matched >= 0;) {
- switch (*p++) {
- case '\\': if (*p) p++; break;
- case '{': matched++; break;
- case '}': matched--; break;
- }
- }
- break;
- case '}':
- break;
- case 0: // end of pattern
- return !*s;
- case '\\': // quote next character
- if (*p) p++;
- default:
- #ifdef WIN32
- if (tolower(*s) != tolower(*(p-1))) return 0;
- #else
- if( *s != *(p-1) ) return 0;
- #endif
- s++;
- break;
- }
- }
- }
- void Flu_File_Chooser :: add_context_handler( int type, const char *ext, const char *name,
- void (*cb)(const char*,int,void*), void *cbd )
- {
- if( cb == NULL )
- return;
- ContextHandler h;
- h.ext = ext ? ext : "";
- h.ext.downcase();
- h.type = type;
- h.name = name;
- h.callback = cb;
- h.callbackData = cbd;
- Flu_File_Chooser::contextHandlers.add( h );
- }
- void Flu_File_Chooser :: add_preview_handler( PreviewWidgetBase *w )
- {
- if( w == NULL )
- return;
- Flu_File_Chooser::previewHandlers.add( w );
- }
- // extensions == NULL implies directories
- void Flu_File_Chooser :: add_type( const char *extensions, const char *short_description, Fl_Image *icon )
- {
- FluSimpleString ext;
- if( extensions )
- ext = extensions;
- else
- ext = "\t"; // indicates a directory
- ext.upcase();
- // are we overwriting an existing type?
- for( int i = 0; i < numTypes; i++ )
- {
- if( types[i].extensions == ext )
- {
- types[i].icon = icon;
- types[i].type = short_description;
- return;
- }
- }
- if( numTypes == typeArraySize )
- {
- int newSize = ( typeArraySize == 0 ) ? 1 : typeArraySize*2; // double the size of the old list (same behavior as STL vector)
- // allocate the new list
- FileTypeInfo* newTypes = new FileTypeInfo[ newSize ];
- // copy the old list to the new list
- for( int i = 0; i < numTypes; i++ )
- {
- newTypes[i].icon = types[i].icon;
- newTypes[i].extensions = types[i].extensions;
- newTypes[i].type = types[i].type;
- }
- // delete the old list and replace it with the new list
- delete[] types;
- types = newTypes;
- typeArraySize = newSize;
- }
- types[numTypes].icon = icon;
- types[numTypes].extensions = ext;
- types[numTypes].type = short_description;
- numTypes++;
- }
- Flu_File_Chooser::FileTypeInfo* Flu_File_Chooser :: find_type( const char *extension )
- {
- FluSimpleString ext;
- if( extension )
- ext = extension;
- else
- ext = "\t"; // indicates a directory
- ext.upcase();
- // lookup the type based on the extension
- for( int i = 0; i < numTypes; i++ )
- {
- // check extension against every token
- FluSimpleString e = types[i].extensions;
- char *tok = strtok( (char*)e.c_str(), " ," );
- while( tok )
- {
- if( ext == tok )
- return &(types[i]);
- tok = strtok( NULL, " ," );
- }
- }
- return NULL;
- }
- Flu_File_Chooser :: Flu_File_Chooser( const char *pathname, const char *pat, int type, const char *title )
- : Fl_Double_Window( 600, 400, title ),
- filename( 70, h()-60, w()-70-85-10, 25, "", this ),
- ok( w()-90, h()-60, 85, 25 ),
- cancel( w()-90, h()-30, 85, 25 ),
- entryPopup( 0, 0, 0, 0 )
- {
- int oldNormalSize = FL_NORMAL_SIZE;
- FL_NORMAL_SIZE = 12;
- fl_register_images();
- _callback = 0;
- _userdata = 0;
- Fl_Double_Window::callback( _hideCB, this );
- Fl_Double_Window::size_range( 600, 400 );
- Fl_Group *g;
- filename.label( filenameTxt.c_str() );
- ok.label( okTxt.c_str() );
- ok.labelsize( FL_NORMAL_SIZE );
- cancel.label( cancelTxt.c_str() );
- cancel.labelsize( FL_NORMAL_SIZE );
- add_type( NULL, directoryTxt.c_str(), &folder_closed );
- for( int j = 0; j < 4; j++ )
- {
- dArrow[j] = "@-12DnArrow " + detailTxt[j];
- uArrow[j] = "@-18UpArrow " + detailTxt[j];
- }
- history = currentHist = NULL;
- walkingHistory = false;
- fileEditing = false;
- #ifdef WIN32
- refreshDrives = true;
- caseSort = false;
- #else
- caseSort = true;
- #endif
- // determine the system paths for the user's home area, desktop, documents, app data, etc
- #ifdef WIN32
- userDesktop = flu_get_special_folder( CSIDL_DESKTOPDIRECTORY );
- userDocs = flu_get_special_folder( CSIDL_PERSONAL );
- // get home area by stripping off to the last '/' from docs
- userHome = userDocs;
- {
- for( int i = userHome.size()-1; i > 0; i-- )
- {
- if( userHome[i] == '/' )
- {
- userHome[i] = '\0';
- break;
- }
- }
- }
- // construct the user desktop path
- //userDesktop = userHome + "/" + desktopTxt;
- win2unix( userDesktop );
- win2unix( userDocs );
- // make sure they don't end in '/'
- if( userDesktop[userDesktop.size()-1] == '/' )
- userDesktop[userDesktop.size()-1] = '\0';
- if( userDocs[userDocs.size()-1] == '/' )
- userDocs[userDocs.size()-1] = '\0';
- // get the actual name of the "My Documents" folder by pulling off the last name in the field
- // we do this because the actual name may vary from country to country
- {
- int slash = userDesktop.rfind( '/' );
- if( slash != -1 )
- desktopTxt = userDesktop.c_str() + slash + 1;
- slash = userDocs.rfind( '/' );
- if( slash != -1 )
- myDocumentsTxt = userDocs.c_str() + slash + 1;
- }
- // make sure they end in '/'
- userHome += "/";
- userDesktop += "/";
- userDocs += "/";
- #else
- {
- char buf[1024];
- fl_filename_expand( buf, 1024, "~/" );
- userHome = buf;
- userDesktop = userHome + "/" + desktopTxt + "/";
- userDocs = "/tmp/";
- }
- #endif
- configFilename = userHome + ".Flu_File_Chooser.favorites";
- selectionType = type;
- filenameEnterCallback = filenameTabCallback = false;
- sortMethod = SORT_NAME;
- lastSelected = NULL;
- filename.labelsize( 12 );
- filename.when( FL_WHEN_ENTER_KEY_ALWAYS );
- filename.callback( _filenameCB, this );
- filename.value( "" );
- Fl_Group *quickIcons = new Fl_Group( 5, 5, 100, h()-10-60 );
- quickIcons->box( FL_DOWN_BOX );
- quickIcons->color( FL_DARK3 );
- Flu_Button *desktopBtn = new Flu_Button( 30, 18, 50, 48 );
- desktopBtn->box( FL_FLAT_BOX );
- desktopBtn->image( desktop );
- desktopBtn->enter_box( FL_THIN_UP_BOX );
- desktopBtn->color( FL_DARK3 );
- desktopBtn->callback( _desktopCB, this );
- {
- Flu_Label *l = new Flu_Label( 5, 62, 100, 20, desktopTxt.c_str() );
- l->labelcolor( FL_WHITE );
- l->align( FL_ALIGN_CENTER );
- }
- Flu_Button *homeBtn = new Flu_Button( 30, 98, 50, 48 );
- homeBtn->box( FL_FLAT_BOX );
- homeBtn->enter_box( FL_THIN_UP_BOX );
- homeBtn->color( FL_DARK3 );
- homeBtn->callback( _homeCB, this );
- {
- #ifdef WIN32
- Flu_Label *l = new Flu_Label( 5, 142, 100, 20, myComputerTxt.c_str() );
- homeBtn->image( my_computer );
- #else
- Flu_Label *l = new Flu_Label( 5, 142, 100, 20, myComputerTxt.c_str() );
- homeBtn->image( home );
- #endif
- l->labelcolor( FL_WHITE );
- l->align( FL_ALIGN_CENTER );
- }
- Flu_Button *documentsBtn = new Flu_Button( 30, 178, 50, 48 );
- documentsBtn->box( FL_FLAT_BOX );
- documentsBtn->enter_box( FL_THIN_UP_BOX );
- documentsBtn->labelcolor( FL_WHITE );
- documentsBtn->color( FL_DARK3 );
- documentsBtn->callback( _documentsCB, this );
- {
- #ifdef WIN32
- Flu_Label *l = new Flu_Label( 5, 222, 100, 20, myDocumentsTxt.c_str() );
- documentsBtn->image( &bigdocuments );
- #else
- Flu_Label *l = new Flu_Label( 5, 222, 100, 20, myDocumentsTxt.c_str() );
- documentsBtn->image( &bigtemporary );
- #endif
- l->labelcolor( FL_WHITE );
- l->align( FL_ALIGN_CENTER );
- }
- Flu_Button *favoritesBtn = new Flu_Button( 30, 258, 50, 48 );
- favoritesBtn->box( FL_FLAT_BOX );
- favoritesBtn->image( favorites );
- favoritesBtn->enter_box( FL_THIN_UP_BOX );
- favoritesBtn->color( FL_DARK3 );
- favoritesBtn->callback( _favoritesCB, this );
- {
- Flu_Label *l = new Flu_Label( 5, 302, 100, 20, favoritesTxt.c_str() );
- l->labelcolor( FL_WHITE );
- l->align( FL_ALIGN_CENTER );
- }
- favoritesList = new Fl_Browser( 0, 0, 0, 0 );
- favoritesList->hide();
- {
- Fl_Group* dummy = new Fl_Group( 5, h()-10-61, 100, 1 );
- quickIcons->resizable( dummy );
- }
- quickIcons->end();
- Fl_Group *dummy = new Fl_Group( 110, 0, w()-110, 70 );
- locationQuickJump = new Fl_Group( 166, 5, w()-171, 8 );
- locationQuickJump->box( FL_NO_BOX );
- locationQuickJump->end();
- location = new Flu_Combo_Tree( 166, 15, w()-171, 22, locationTxt.c_str() );
- location->editable( false );
- location->pop_height( 200 );
- location->tree.all_branches_always_open( true );
- #ifdef WIN32
- location->tree.show_root( false );
- #endif
- location->tree.show_connectors( false );
- location->tree.horizontal_gap( -10 );
- location->tree.show_leaves( false );
- location->callback( _locationCB, this );
- ////////////////////////////////////////////////////////////////
- g = new Fl_Group( 110, 40, w()-110, 30 ); // group enclosing all the buttons at top
- hiddenFiles = new Fl_Check_Button( 110, 43, 130, 25, showHiddenTxt.c_str() );
- hiddenFiles->callback( reloadCB, this );
- #ifdef WIN32
- hiddenFiles->hide();
- #endif
- backBtn = new Flu_Button( 285, 43, 25, 25, "@<-" );
- backBtn->labelcolor( fl_rgb_color( 80, 180, 200 ) );
- backBtn->labelsize( 16 );
- backBtn->box( FL_FLAT_BOX );
- backBtn->enter_box( FL_THIN_UP_BOX );
- backBtn->callback( _backCB, this );
- backBtn->tooltip( backTTxt.c_str() );
- forwardBtn = new Flu_Button( 310, 43, 25, 25, "@->" );
- forwardBtn->labelcolor( fl_rgb_color( 80, 180, 200 ) );
- forwardBtn->labelsize( 16 );
- forwardBtn->box( FL_FLAT_BOX );
- forwardBtn->enter_box( FL_THIN_UP_BOX );
- forwardBtn->callback( _forwardCB, this );
- forwardBtn->tooltip( forwardTTxt.c_str() );
- upDirBtn = new Flu_Button( 335, 43, 25, 25 );
- upDirBtn->image( up_folder_img );
- upDirBtn->box( FL_FLAT_BOX );
- upDirBtn->enter_box( FL_THIN_UP_BOX );
- upDirBtn->callback( upDirCB, this );
- upDirBtn->tooltip( upTTxt.c_str() );
- reloadBtn = new Flu_Button( 360, 43, 25, 25 );
- reloadBtn->image( reload );
- reloadBtn->box( FL_FLAT_BOX );
- reloadBtn->enter_box( FL_THIN_UP_BOX );
- reloadBtn->callback( reloadCB, this );
- reloadBtn->tooltip( reloadTTxt.c_str() );
- {
- Flu_Separator *sep = new Flu_Separator( 385, 42, 10, 28 );
- sep->type( Flu_Separator::VERTICAL );
- sep->box( FL_ENGRAVED_BOX );
- }
- trashBtn = new Flu_Button( 395, 43, 25, 25 );
- trashBtn->image( trash );
- trashBtn->box( FL_FLAT_BOX );
- trashBtn->enter_box( FL_THIN_UP_BOX );
- trashBtn->callback( _trashCB, this );
- trashBtn->tooltip( trashTTxt.c_str() );
- newDirBtn = new Flu_Button( 420, 43, 25, 25 );
- newDirBtn->image( new_folder );
- newDirBtn->box( FL_FLAT_BOX );
- newDirBtn->enter_box( FL_THIN_UP_BOX );
- newDirBtn->callback( _newFolderCB, this );
- newDirBtn->tooltip( newDirTTxt.c_str() );
- addFavoriteBtn = new Flu_Button( 445, 43, 25, 25 );
- addFavoriteBtn->image( add_to_favorite_folder );
- addFavoriteBtn->box( FL_FLAT_BOX );
- addFavoriteBtn->enter_box( FL_THIN_UP_BOX );
- addFavoriteBtn->callback( _addToFavoritesCB, this );
- addFavoriteBtn->tooltip( addFavoriteTTxt.c_str() );
- {
- Flu_Separator *sep = new Flu_Separator( 470, 42, 10, 28 );
- sep->type( Flu_Separator::VERTICAL );
- sep->box( FL_ENGRAVED_BOX );
- }
- previewBtn = new Flu_Button( 482, 43, 23, 25 );
- previewBtn->type( FL_TOGGLE_BUTTON );
- previewBtn->image( preview_img );
- previewBtn->callback( _previewCB, this );
- previewBtn->tooltip( previewTTxt.c_str() );
- {
- Fl_Group *g2 = new Fl_Group( 511, 43, 81, 25 );
- fileListBtn = new Flu_Button( 511, 43, 25, 25 );
- fileListBtn->type( FL_RADIO_BUTTON );
- fileListBtn->value(1);
- fileListBtn->callback( _listModeCB, this );
- fileListBtn->image( file_list_img );
- fileListBtn->tooltip( listTTxt.c_str() );
- fileListWideBtn = new Flu_Button( 540, 43, 25, 25 );
- fileListWideBtn->type( FL_RADIO_BUTTON );
- fileListWideBtn->callback( _listModeCB, this );
- fileListWideBtn->image( file_listwide_img );
- fileListWideBtn->tooltip( wideListTTxt.c_str() );
- fileDetailsBtn = new Flu_Button( 569, 43, 25, 25 );
- fileDetailsBtn->type( FL_RADIO_BUTTON );
- fileDetailsBtn->image( fileDetails );
- fileDetailsBtn->callback( _listModeCB, this );
- fileDetailsBtn->tooltip( detailTTxt.c_str() );
- g2->end();
- }
- g->resizable( hiddenFiles );
- g->end();
- dummy->resizable( location );
- dummy->end();
- ////////////////////////////////////////////////////////////////
- previewTile = new PreviewTile( 110, 70, w()-110-5, h()-80-40-15, this );
- fileGroup = new Fl_Group( 110, 70, w()-120-5, h()-80-40-15 );
- {
- fileGroup->box( FL_DOWN_FRAME );
- filelist = new FileList( fileGroup->x()+2, fileGroup->y()+2, fileGroup->w()-4, fileGroup->h()-4, this );
- filelist->box( FL_FLAT_BOX );
- filelist->color( FL_WHITE );
- filelist->type( FL_HORIZONTAL );
- filelist->spacing( 4, 1 );
- filelist->scrollbar.linesize( DEFAULT_ENTRY_WIDTH+4 );
- filelist->end();
- fileDetailsGroup = new Fl_Group( fileGroup->x()+2, fileGroup->y()+2, fileGroup->w()-4, fileGroup->h()-4 );
- filecolumns = new FileColumns( fileGroup->x()+2, fileGroup->y()+2, fileGroup->w()-4, 20, this );
- filescroll = new Fl_Scroll( fileGroup->x()+2, fileGroup->y()+22, fileGroup->w()-4, fileGroup->h()-20-4 );
- filescroll->color( FL_WHITE );
- filescroll->scrollbar.linesize( 20 );
- filescroll->box( FL_FLAT_BOX );
- filescroll->type( Fl_Scroll::VERTICAL );
- {
- filedetails = new FileDetails( fileGroup->x()+2, fileGroup->y()+22, fileGroup->w()-4, fileGroup->h()-20-4, this );
- filedetails->end();
- }
- filescroll->end();
- fileDetailsGroup->end();
- fileDetailsGroup->resizable( filescroll );
- fileGroup->resizable( filelist );
- }
- fileGroup->end();
- previewGroup = new PreviewGroup( fileGroup->x()+fileGroup->w(), fileGroup->y(), previewTile->w()-fileGroup->w(), fileGroup->h(), this );
- previewGroup->end();
- {
- Fl_Box *b = new Fl_Box( previewTile->x()+250, previewTile->y(), previewTile->w()-350, previewTile->h() );
- previewTile->add_resizable( *b );
- }
- previewTile->end();
- previewTile->position( previewGroup->x(), previewGroup->y(), previewTile->x()+previewTile->w(), previewGroup->y() );
- previewTile->last = previewTile->x()+previewTile->w()-200;
- resizable( previewTile );
- filePattern = new Flu_Combo_List( 70, h()-30, w()-70-85-10, 25, fileTypesTxt.c_str() );
- filePattern->editable( false );
- filePattern->callback( reloadCB, this );
- filePattern->pop_height( 200 );
- ok.callback( _okCB, this );
- cancel.callback( _cancelCB, this );
- {
- g = new Fl_Group( 0, h()-60, w(), 30 );
- g->end();
- g->add( filename );
- g->add( ok );
- g->resizable( filename );
- g = new Fl_Group( 0, h()-30, w(), 30 );
- g->end();
- g->add( filePattern );
- g->add( cancel );
- g->resizable( filePattern );
- }
- end();
- FL_NORMAL_SIZE = oldNormalSize;
- char buf[1024];
- // try to load the favorites
- {
- FILE *f = fopen( configFilename.c_str(), "r" );
- if( f )
- {
- buf[0] = '\0';
- while( !feof(f) )
- {
- fgets( buf, 1024, f );
- char *newline = strrchr( buf, '\n' );
- if( newline )
- *newline = '\0';
- if( strlen( buf ) > 0 )
- {
- // eliminate duplicates
- bool duplicate = false;
- for( int i = 1; i <= favoritesList->size(); i++ )
- {
- if( streq( buf, favoritesList->text(i) ) )
- {
- duplicate = true;
- break;
- }
- }
- if( !duplicate )
- favoritesList->add( buf );
- }
- }
- fclose( f );
- }
- }
- if( !imgTxtPreview )
- {
- imgTxtPreview = new ImgTxtPreview();
- // make the text previewer the first one
- Flu_File_Chooser::previewHandlers.insert( 0, imgTxtPreview );
- }
- pattern( pat );
- default_file_icon( &default_file );
- cd( NULL ); // prime with the current directory
- clear_history();
- cd( pathname );
- // if pathname does not start with "/" or "~", set the filename to it
- if( pathname && pathname[0] != '/' && pathname[1] != ':' && pathname[0] != '~' )
- filename.value( pathname );
- }
- Flu_File_Chooser :: ~Flu_File_Chooser()
- {
- //Fl::remove_timeout( Entry::_editCB );
- Fl::remove_timeout( Flu_File_Chooser::delayedCdCB );
- Fl::remove_timeout( Flu_File_Chooser::selectCB );
- for( int i = 0; i < locationQuickJump->children(); i++ )
- free( (void*)locationQuickJump->child(i)->label() );
- filelist->clear();
- filedetails->clear();
- clear_history();
- }
- void Flu_File_Chooser :: hideCB()
- {
- // the user hid the browser by pushing the "X"
- // this is the same as cancel
- cancelCB();
- }
- void Flu_File_Chooser :: cancelCB()
- {
- filename.value("");
- filename.position( filename.size(), filename.size() );
- unselect_all();
- do_callback();
- hide();
- }
- void Flu_File_Chooser :: do_callback()
- {
- if( _callback )
- _callback( this, _userdata );
- }
- void Flu_File_Chooser :: pattern( const char *p )
- {
- // just like in Fl_File_Chooser, we accept tab, |, and ; delimited strings like this:
- // "Description (patterns)" or just "patterns" where patterns is
- // of the form *.xxx or *.{xxx,yyy,zzz}}
- rawPattern = p;
- // clear out the old
- filePattern->list.clear();
- filePattern->input.value( "" );
- patterns.clear();
- if( p == 0 )
- p = "*";
- else if( p[0] == '\0' )
- p = "*";
- FluSimpleString pat = p, pattern;
- bool addedAll = false;
- const char *next = strtok( (char*)pat.c_str(), "\t|;" );
- const char *start;
- while( next )
- {
- if( next[0] == '\0' )
- break;
- // eat whitespace
- while( isspace( *next ) )
- next++;
- // degenerate check
- if( strcmp( next, "*" ) == 0 )
- {
- addedAll = true;
- filePattern->list.add( allFilesTxt.c_str() );
- patterns.add( "*" );
- next = strtok( NULL, "\t|;" );
- continue;
- }
- // extract the patterns from the substring
- if( next[0] != '*' ) // starts with description
- {
- // the pattern starts after the first '('
- start = strchr( next, '(' );
- if( !start ) // error: couldn't find the '('
- {
- next = strtok( NULL, "\t|;" );
- continue;
- }
- start++; // skip the '('
- }
- else
- start = next;
- if( start[0] != '*' )
- {
- next = strtok( NULL, "\t|;" );
- continue;
- }
- start++; // skip the '*'
- if( start[0] != '.' )
- {
- next = strtok( NULL, "\t|;" );
- continue;
- }
- start++; // skip the '.'
- if( start[0] == '{' )
- {
- // the pattern is between '{' and '}'
- pattern = start+1;
- }
- else
- pattern = start;
- // remove the last '}'
- int brace = pattern.find( '}' );
- if( brace != -1 )
- pattern[brace] = '\0';
- // remove the last ')'
- int paren = pattern.find( ')' );
- if( paren != -1 )
- pattern[paren] = '\0';
- if( pattern.size() )
- {
- // add the whole string to the list
- filePattern->list.add( next );
- patterns.add( pattern );
- }
- // advance to the pattern token
- next = strtok( NULL, "\t|;" );
- }
- // add all files
- if( !addedAll )
- {
- filePattern->list.add( allFilesTxt.c_str() );
- patterns.add( "*" );
- }
- // choose the first added item
- filePattern->value( filePattern->list.text(1) );
- }
- int Flu_File_Chooser :: handle( int event )
- {
- if( Fl_Double_Window::callback() != _hideCB )
- {
- _callback = Fl_Double_Window::callback();
- _userdata = Fl_Double_Window::user_data();
- Fl_Double_Window::callback( _hideCB, this );
- }
- if( Fl_Double_Window::handle( event ) )
- return 1;
- else if( event == FL_KEYDOWN && Fl::event_key(FL_Escape) )
- {
- cancel.do_callback();
- return 1;
- }
- else if( event == FL_KEYDOWN && Fl::event_key('a') && Fl::event_state(FL_CTRL) )
- {
- select_all();
- return 1;
- }
- else
- return 0;
- }
- void Flu_File_Chooser :: newFolderCB()
- {
- // start with the name "New Folder". while the name exists, keep appending a number (1..2..etc)
- FluSimpleString newName = defaultFolderNameTxt.c_str(), path = currentDir + newName;
- int count = 1;
- int i;
- for(;;)
- {
- bool found = false;
- // see if any entry already has that name
- Fl_Group *g = getEntryGroup();
- for( i = 0; i < g->children(); i++ )
- {
- if( ((Entry*)g->child(i))->filename == newName )
- {
- found = true;
- break;
- }
- }
- // since an entry already exists, change the name and try again
- if( found )
- {
- char buf[16];
- sprintf( buf, "%d", count++ );
- newName = defaultFolderNameTxt.c_str() + FluSimpleString(buf);
- path = currentDir + newName;
- }
- else
- break;
- }
- // try to create the folder
- #if ( defined WIN32 || defined MINGW ) && !defined CYGWIN
- if( mkdir( path.c_str() ) != 0 )
- #else
- if( mkdir( path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) != 0 )
- #endif
- {
- fl_alert( createFolderErrTxt.c_str(), newName.c_str() );
- return;
- }
- // create a new entry with the name of the new folder. add to either the list or the details
- Entry *entry = new Entry( newName.c_str(), ENTRY_DIR, fileDetailsBtn->value(), this );
- if( !fileDetailsBtn->value() )
- filelist->add( *entry );
- else
- filedetails->add( *entry );
- // switch that entry to input mode and scroll the browser to it
- entry->editCB();
- /*
- entry->editMode = 2;
- entry->value( entry->filename.c_str() );
- entry->take_focus();
- entry->position( 0, entry->filename.size() );
- entry->redraw();
- */
- if( !fileDetailsBtn->value() )
- filelist->scroll_to( entry );
- else
- filedetails->scroll_to( entry );
- }
- void Flu_File_Chooser :: recursiveScan( const char *dir, FluStringVector *files )
- {
- dirent **e;
- char *name;
- FluSimpleString fullpath;
- int num = fl_filename_list( dir, &e );
- for( int i = 0; i < num; i++ )
- {
- name = e[i]->d_name;
- // if 'name' ends in '/' or '\', remove it
- if( name[strlen(name)-1] == '/' || name[strlen(name)-1] == '\\' )
- name[strlen(name)-1] = '\0';
- // ignore the "." and ".." names
- if( strcmp( name, "." ) == 0 || strcmp( name, ".." ) == 0 )
- continue;
- // file or directory?
- fullpath = dir;
- fullpath += "/";
- fullpath += name;
- if( fl_filename_isdir( fullpath.c_str() ) != 0 )
- recursiveScan( fullpath.c_str(), files );
- files->add( fullpath );
- }
- files->add( dir );
- }
- void Flu_File_Chooser :: trashCB( bool recycle )
- {
- // linux doesn't have a recycle bin
- #ifndef WIN32
- recycle = false;
- #endif
- bool inFavorites = ( currentDir == FAVORITES_UNIQUE_STRING );
- if( inFavorites )
- recycle = false;
- // see how many files are selected
- FluSimpleString name;
- int selected = 0;
- int i;
- const char *first = "";
- Fl_Group *g = getEntryGroup();
- for( i = 0; i < g->children(); i++ )
- {
- if( ((Entry*)g->child(i))->selected )
- {
- if( selected == 0 )
- first = ((Entry*)g->child(i))->filename.c_str();
- selected++;
- }
- }
- if( selected )
- {
- if( selected == 1 )
- {
- if( recycle )
- {
- if( !fl_ask( "Really send '%s' to the Recycle Bin?", first ) )
- return;
- }
- else
- {
- if( !fl_ask( "Really delete '%s'?", first ) )
- return;
- }
- }
- else
- {
- if( recycle )
- {
- if( !fl_ask( "Really send these %d files to the Recycle Bin?", selected ) )
- return;
- }
- else
- {
- if( !fl_ask( "Really delete these %d files?", selected ) )
- return;
- }
- }
- if( inFavorites )
- {
- for( i = 0; i < g->children(); )
- {
- Entry *e = ((Entry*)g->child(i));
- if( e->selected )
- {
- favoritesList->remove(i+1);
- g->remove( *e );
- delete e;
- }
- else
- i++;
- }
- // save the favorites
- FILE *f = fopen( configFilename.c_str(), "w" );
- if( f )
- {
- for( i = 1; i <= favoritesList->size(); i++ )
- fprintf( f, "%s\n", favoritesList->text(i) );
- fclose( f );
- }
- cd( FAVORITES_UNIQUE_STRING );
- return;
- }
- #ifdef WIN32
- SHFILEOPSTRUCT fileop;
- memset( &fileop, 0, sizeof(SHFILEOPSTRUCT) );
- fileop.fFlags = FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMATION;
- if( recycle )
- fileop.fFlags |= FOF_ALLOWUNDO;
- fileop.wFunc = FO_DELETE;
- fileop.pTo = NULL;
- #endif
- for( i = 0; i < g->children(); i++ )
- {
- if( ((Entry*)g->child(i))->selected )
- {
- int result = 0;
- name = currentDir + ((Entry*)g->child(i))->filename;
- // if directory, recursively remove
- if( ((Entry*)g->child(i))->type == ENTRY_DIR )
- {
- // if we are recycling in windows, then the recursive part happens automatically
- #ifdef WIN32
- if( !recycle )
- #endif
- {
- Fl_Group::current(0);
- Fl_Window *win = new Fl_Window( 200, 100, "Notice" );
- Flu_Label *label = new Flu_Label( 30, 30, 150, 30, "Preparing to delete..." );
- win->end();
- win->show();
- Fl::check();
- // recursively build a list of all files that will be deleted
- FluStringVector files;
- recursiveScan( name.c_str(), &files );
- // delete all the files
- label->label( "Deleting files..." );
- for( unsigned int i = 0; i < files.size(); i++ )
- {
- if( ::remove( files[i].c_str() ) != 0 )
- {
- win->hide();
- delete win;
- cd( "./" );
- return;
- }
- }
- win->hide();
- delete win;
- Fl::check();
- continue;
- }
- }
- #ifdef WIN32
- // this moves files to the recycle bin, depending on the value of 'recycle'
- {
- int len = name.size();
- char *buf = (char*)malloc( len+2 );
- strcpy( buf, name.c_str() );
- buf[len+1] = '\0'; // have to have 2 '\0' at the end
- fileop.pFrom = buf;
- result = SHFileOperation( &fileop );
- free( buf );
- }
- #else
- result = ::remove( name.c_str() );
- #endif
- // if remove fails, report an error
- if( result != 0 )
- {
- fl_alert( deleteFileErrTxt.c_str(), name.c_str() );
- cd( "./" );
- return;
- }
- }
- }
- // refresh this directory
- cd( "./" );
- }
- }
- void Flu_File_Chooser :: updateLocationQJ()
- {
- const char *path = location->value();
- for( int i = 0; i < locationQuickJump->children(); i++ )
- free( (void*)locationQuickJump->child(i)->label() );
- locationQuickJump->clear();
- fl_font( location->input.textfont(), location->input.textsize() );
- const char *next = path;
- const char *slash = strchr( next, '/' );
- char *blank = strdup( path );
- int offset = 0;
- while( slash )
- {
- memset( blank, 0, strlen(path) );
- slash++;
- memcpy( blank, next, slash-next );
- int w = 0, h = 0;
- fl_measure( blank, w, h );
- if( blank[0] == '/' )
- w += Fl::box_dx( location->box() );
- memset( blank, 0, strlen(path) );
- memcpy( blank, path, slash-path );
- Fl_Button *b = new Fl_Button( locationQuickJump->x()+offset, locationQuickJump->y(), w, locationQuickJump->h(), strdup(blank) );
- b->labeltype( FL_NO_LABEL );
- b->callback( _locationQJCB, this );
- b->tooltip( b->label() );
- offset += w;
- locationQuickJump->add( b );
- next = slash;
- slash = strchr( next, '/' );
- }
- Fl_Button *b = new Fl_Button( locationQuickJump->x()+offset, locationQuickJump->y(), 1, locationQuickJump->h(), strdup("") );
- b->box( FL_NO_BOX );
- b->labeltype( FL_NO_LABEL );
- locationQuickJump->add( b );
- locationQuickJump->resizable( b );
- free( blank );
- }
- void Flu_File_Chooser :: favoritesCB()
- {
- cd( FAVORITES_UNIQUE_STRING );
- }
- void Flu_File_Chooser :: myComputerCB()
- {
- cd( "/" );
- }
- void Flu_File_Chooser :: documentsCB()
- {
- cd( userDocs.c_str() );
- }
- Flu_File_Chooser :: FileInput :: FileInput( int x, int y, int w, int h, const char *l, Flu_File_Chooser *c )
- : Fl_Input( x, y, w, h, l )
- {
- chooser = c;
- }
- Flu_File_Chooser :: FileInput :: ~FileInput()
- {
- }
- int Flu_File_Chooser :: FileInput :: handle( int event )
- {
- if( event == FL_KEYDOWN )
- {
- if( Fl::event_key(FL_Tab) )
- {
- chooser->filenameTabCallback = true;
- FluSimpleString v(value());
- #ifdef WIN32
- // turn "C:" into "C:/"
- if( v.size() >= 2 )
- if( v[1] == ':' && v[2] == '\0' )
- {
- v += "/";
- value( v.c_str() );
- position( size(), size() );
- }
- #endif
- chooser->delay_cd( v + "*" );
- return 1;
- }
- else if( Fl::event_key(FL_Left) )
- {
- if( Fl_Input::position() == 0 )
- return 1;
- else
- return Fl_Input::handle( event );
- }
- else if( Fl::event_key(FL_Right) )
- {
- if( Fl_Input::position() == (int)strlen(Fl_Input::value()) )
- return 1;
- else
- return Fl_Input::handle( event );
- }
- else if( Fl::event_key(FL_Up) || Fl::event_key(FL_Down) )
- {
- chooser->getEntryContainer()->take_focus();
- if( !chooser->lastSelected )
- {
- if( chooser->getEntryGroup()->children() )
- {
- Flu_File_Chooser::Entry *e = (Flu_File_Chooser::Entry*)chooser->getEntryGroup()->child(0);
- e->selected = true;
- chooser->lastSelected = e;
- e->redraw();
- }
- }
- return chooser->getEntryContainer()->handle( event );
- }
- }
- return Fl_Input::handle( event );
- }
- Flu_File_Chooser :: PreviewTile :: PreviewTile( int x, int y, int w, int h, Flu_File_Chooser *c )
- : Fl_Tile( x, y, w, h )
- {
- chooser = c;
- }
- int Flu_File_Chooser :: PreviewTile :: handle( int event )
- {
- // if we're not in preview mode, then the user isn't allowed to resize the tile
- if( !chooser->previewBtn->value() )
- return Fl_Group::handle( event );
- if( event == FL_DRAG )
- {
- // the user is probably dragging to resize the columns
- // update the sizes for each entry
- chooser->updateEntrySizes();
- chooser->redraw();
- }
- return Fl_Tile::handle(event);
- }
- Flu_File_Chooser :: PreviewWidgetBase :: PreviewWidgetBase()
- : Fl_Group( 0, 0, 0, 0 )
- {
- }
- Flu_File_Chooser :: PreviewWidgetBase :: ~PreviewWidgetBase()
- {
- }
- Flu_File_Chooser :: PreviewGroup :: PreviewGroup( int x, int y, int w, int h, Flu_File_Chooser *c )
- : Fl_Group( x, y, w, h )
- {
- box( FL_DOWN_BOX );
- align( FL_ALIGN_CENTER | FL_ALIGN_CLIP );
- labelsize( 60 );
- labelfont( FL_HELVETICA );
- chooser = c;
- handled = 0;
- lastFile = "";
- }
- void Flu_File_Chooser :: PreviewGroup :: draw()
- {
- if( !chooser->previewBtn->value() )
- return;
- if( file.size() == 0 )
- return;
- FILE *f = fopen( file.c_str(), "rb" );
- if( !f )
- {
- label( "" );
- Fl_Group::draw();
- return;
- }
- fclose( f );
- if( lastFile != file )
- {
- lastFile = file;
- handled = 0;
- PreviewWidgetBase *next;
- for( int i = chooser->previewHandlers.size()-1; i >= 0; i-- )
- {
- next = chooser->previewHandlers[i];
- next->hide();
- if( !handled )
- {
- Fl_Group *p = next->parent();
- Fl_Group::add( next );
- if( next->preview( file.c_str() ) != 0 )
- {
- handled = next;
- }
- Fl_Group::remove( *next );
- if( p )
- p->add( next );
- }
- }
- }
- if( handled == 0 )
- {
- label( "?" );
- Fl_Group::draw();
- }
- else
- {
- label( "" );
- Fl_Group *p = handled->parent();
- handled->show();
- Fl_Group::add( handled );
- handled->resize( x()+Fl::box_dx(box()), y()+Fl::box_dy(box()),
- w()-Fl::box_dw(box()), h()-Fl::box_dh(box()) );
- Fl_Group::draw();
- Fl_Group::remove( *handled );
- handled->hide();
- if( p )
- p->add( handled );
- }
- }
- // adapted from Fl_File_Chooser2.cxx : update_preview()
- int Flu_File_Chooser :: ImgTxtPreview :: preview( const char *filename )
- {
- Fl_Shared_Image *img, // New image
- *oldimg; // Old image
- int pbw, pbh; // Width and height of preview box
- int w, h; // Width and height of preview image
- window()->cursor( FL_CURSOR_WAIT );
- Fl::check();
- img = Fl_Shared_Image::get( filename );
- if( img )
- {
- window()->cursor( FL_CURSOR_DEFAULT );
- Fl::check();
- }
- oldimg = (Fl_Shared_Image*)image();
- if( oldimg )
- oldimg->release();
- image(0);
- if( !img )
- {
- // Try reading the first 1k of data for a label...
- FILE *f = fopen( filename, "rb" );
- if( f )
- {
- int bytes = fread( previewTxt, 1, sizeof(previewTxt) - 1, f );
- previewTxt[bytes] = '\0';
- fclose( f );
- }
- else
- return 0;
- window()->cursor( FL_CURSOR_DEFAULT );
- Fl::check();
- // Scan the buffer for printable chars...
- unsigned char *ptr;
- for( ptr = previewTxt; *ptr && (isprint(*ptr) || isspace(*ptr)); ptr++ ) {}
- if( *ptr || ptr == previewTxt )
- {
- // Non-printable file - can't handle
- return 0;
- }
- else
- {
- // Show the first 1k of text...
- label( (const char*)previewTxt );
- align((Fl_Align)(FL_ALIGN_CLIP | FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_TOP));
- labelsize( 12 );
- labelfont( FL_COURIER );
- }
- }
- else if( img->w() > 0 && img->h() > 0 )
- {
- pbw = this->w() - 20;
- pbh = this->h() - 20;
- pbw = (pbw < 10) ? 10 : pbw;
- pbh = (pbh < 10) ? 10 : pbh;
- if( img->w() > pbw || img->h() > pbh )
- {
- w = pbw;
- h = int(float(w*img->h()) / float(img->w()));
- if( h > pbh )
- {
- h = pbh;
- w = int(float(h*img->w()) / float(img->h()));
- }
- oldimg = (Fl_Shared_Image *)img->copy(w, h);
- image((Fl_Image *)oldimg);
- img->release();
- }
- else
- image((Fl_Image *)img);
- align( FL_ALIGN_CLIP );
- label(0);
- }
- redraw();
- return 1;
- }
- void Flu_File_Chooser :: previewCB()
- {
- if( previewBtn->value() )
- {
- fileGroup->resize( fileGroup->x(), fileGroup->y(), previewTile->last-fileGroup->x(), fileGroup->h() );
- previewGroup->resize( previewTile->last, previewGroup->y(), previewTile->w()-fileGroup->w(), previewGroup->h() );
- previewGroup->show();
- }
- else
- {
- previewTile->last = previewGroup->x();
- fileGroup->resize( fileGroup->x(), fileGroup->y(), previewTile->w(), fileGroup->h() );
- previewGroup->resize( previewTile->x()+previewTile->w(), previewGroup->y(), 0, previewGroup->h() );
- previewGroup->hide();
- }
- previewGroup->redraw();
- previewTile->init_sizes();
- fileDetailsGroup->parent()->init_sizes();
- updateEntrySizes();
- redraw();
- if( previewBtn->value() )
- {
- Fl::check();
- previewGroup->redraw();
- }
- }
- void Flu_File_Chooser :: sortCB( Fl_Widget *w )
- {
- // if the sort method is already selected, toggle the REVERSE bit
- if( w == detailNameBtn )
- {
- if( sortMethod & SORT_NAME )
- sortMethod ^= SORT_REVERSE;
- else
- sortMethod = SORT_NAME;
- }
- else if( w == detailSizeBtn )
- {
- if( sortMethod & SORT_SIZE )
- sortMethod ^= SORT_REVERSE;
- else
- sortMethod = SORT_SIZE;
- }
- else if( w == detailDateBtn )
- {
- if( sortMethod & SORT_DATE )
- sortMethod ^= SORT_REVERSE;
- else
- sortMethod = SORT_DATE;
- }
- else if( w == detailTypeBtn )
- {
- if( sortMethod & SORT_TYPE )
- sortMethod ^= SORT_REVERSE;
- else
- sortMethod = SORT_TYPE;
- }
- bool reverse = ( sortMethod & SORT_REVERSE );
- detailNameBtn->label( detailTxt[0].c_str() );
- detailSizeBtn->label( detailTxt[1].c_str() );
- detailDateBtn->label( detailTxt[2].c_str() );
- detailTypeBtn->label( detailTxt[3].c_str() );
- switch( sortMethod & ~SORT_REVERSE )
- {
- case SORT_NAME: detailNameBtn->label( reverse ? dArrow[0].c_str() : uArrow[0].c_str() ); break;
- case SORT_SIZE: detailSizeBtn->label( reverse ? dArrow[1].c_str() : uArrow[1].c_str() ); break;
- case SORT_DATE: detailDateBtn->label( reverse ? dArrow[2].c_str() : uArrow[2].c_str() ); break;
- case SORT_TYPE: detailTypeBtn->label( reverse ? dArrow[3].c_str() : uArrow[3].c_str() ); break;
- }
- filelist->sort();
- filedetails->sort();
- }
- Flu_File_Chooser :: CBTile :: CBTile( int x, int y, int w, int h, Flu_File_Chooser *c )
- : Fl_Tile( x, y, w, h )
- {
- chooser = c;
- }
- int Flu_File_Chooser :: CBTile :: handle( int event )
- {
- if( event == FL_DRAG )
- {
- // the user is probably dragging to resize the columns
- // update the sizes for each entry
- chooser->updateEntrySizes();
- chooser->redraw();
- }
- return Fl_Tile::handle(event);
- }
- Flu_File_Chooser :: FileColumns :: FileColumns( int x, int y, int w, int h, Flu_File_Chooser *c )
- : Fl_Tile( x, y, w, h )
- {
- chooser = c;
- W1 = int(float(w)*0.35f);
- W2 = int(float(w)*0.20f);
- W3 = int(float(w)*0.15f);
- W4 = w-W1-W2-W3;
- Fl_Box *box = new Fl_Box( x+50, y, w-200, h );
- add_resizable( *box );
- c->detailNameBtn = new Flu_Button( x, y, W1, h, detailTxt[0].c_str() );
- c->detailNameBtn->align( FL_ALIGN_CLIP );
- c->detailNameBtn->callback( Flu_File_Chooser::_sortCB, c );
- {
- CBTile *tile = new CBTile( x+W1, y, W2+W3+W4, h, c );
- Fl_Box *box = new Fl_Box( tile->x()+50, tile->y(), tile->w()-150, tile->h() );
- tile->add_resizable( *box );
- c->detailTypeBtn = new Flu_Button( x+W1, y, W2, h, detailTxt[3].c_str() );
- c->detailTypeBtn->align( FL_ALIGN_CLIP );
- c->detailTypeBtn->callback( Flu_File_Chooser::_sortCB, c );
- {
- CBTile *tile = new CBTile( x+W1+W2, y, W3+W4, h, c );
- Fl_Box *box = new Fl_Box( tile->x()+50, tile->y(), tile->w()-100, tile->h() );
- tile->add_resizable( *box );
- c->detailSizeBtn = new Flu_Button( x+W1+W2, y, W3, h, detailTxt[1].c_str() );
- c->detailSizeBtn->align( FL_ALIGN_CLIP );
- c->detailSizeBtn->callback( Flu_File_Chooser::_sortCB, c );
- c->detailDateBtn = new Flu_Button( x+W1+W2+W3, y, W4, h, detailTxt[2].c_str() );
- c->detailDateBtn->align( FL_ALIGN_CLIP );
- c->detailDateBtn->callback( Flu_File_Chooser::_sortCB, c );
- tile->end();
- }
- tile->end();
- }
- end();
- }
- Flu_File_Chooser :: FileColumns :: ~FileColumns()
- {
- }
- void Flu_File_Chooser :: FileColumns :: resize( int x, int y, int w, int h )
- {
- // TODO resize the buttons/tiles according to their stored relative sizes
- Fl_Tile::resize( x, y, w, h );
- }
- int Flu_File_Chooser :: FileColumns :: handle( int event )
- {
- if( event == FL_DRAG )
- {
- // the user is probably dragging to resize the columns
- // update the sizes for each entry
- chooser->updateEntrySizes();
- chooser->redraw();
- }
- return Fl_Tile::handle(event);
- }
- void Flu_File_Chooser :: filenameCB()
- {
- filenameEnterCallback = true;
- //cd( filename.value() );
- okCB();
- }
- inline bool _isProbablyAPattern( const char *s )
- {
- return( strpbrk( s, "*;|[]?" ) != NULL );
- }
- void Flu_File_Chooser :: okCB()
- {
- // if exactly one directory is selected and we are not choosing directories,
- // cd to that directory.
- if( !( selectionType & DIRECTORY ) && !( selectionType & STDFILE ) )
- {
- Fl_Group *g = getEntryGroup();
- FluSimpleString dir;
- int count = 0;
- for( int i = 0; i < g->children(); i++ )
- {
- if( ((Flu_File_Chooser::Entry*)g->child(i))->selected )
- {
- count++;
- dir = ((Flu_File_Chooser::Entry*)g->child(i))->filename;
- }
- }
- if( count == 1 )
- {
- FluSimpleString path = currentDir + dir;
- if( fl_filename_isdir( path.c_str() ) )
- {
- cd( dir.c_str() );
- return;
- }
- }
- }
- // only hide if the filename is not blank or the user is choosing directories,
- // in which case use the current directory
- if( selectionType & DIRECTORY ||
- ( (selectionType & STDFILE) && fl_filename_isdir( (currentDir+filename.value()).c_str() ) )
- )
- {
- #ifdef WIN32
- if( myComputerTxt == filename.value() )
- {
- myComputerCB();
- return;
- }
- #endif
- if( !(selectionType & MULTI ) )
- {
- if( strlen( filename.value() ) != 0 )
- cd( filename.value() );
- filename.value( currentDir.c_str() );
- filename.position( filename.size(), filename.size() );
- }
- do_callback();
- hide();
- }
- else
- {
- if( strlen( filename.value() ) != 0 )
- {
- if( _isProbablyAPattern( filename.value() ) )
- {
- cd( filename.value() );
- return;
- }
- #ifdef WIN32
- if( filename.value()[1] == ':' )
- #else
- if( filename.value()[0] == '/' )
- #endif
- if( fl_filename_isdir( filename.value() ) )
- {
- filename.value( "" );
- return;
- }
- // prepend the path
- FluSimpleString path = currentDir + filename.value();
- filename.value( path.c_str() );
- filename.position( filename.size(), filename.size() );
- do_callback();
- hide();
- }
- }
- }
- void Flu_File_Chooser :: homeCB()
- {
- #ifdef WIN32
- cd( "/" );
- #else
- cd( userHome.c_str() );
- #endif
- }
- void Flu_File_Chooser :: desktopCB()
- {
- cd( userDesktop.c_str() );
- }
- #define QSCANL( field ) \
- while( ((Flu_File_Chooser::Entry*)array[left])->field < \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) left++
- #define QSCANR( field ) \
- while( ((Flu_File_Chooser::Entry*)array[right])->field > \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) right--
- #define RQSCANL( field ) \
- while( ((Flu_File_Chooser::Entry*)array[left])->field > \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) left++
- #define RQSCANR( field ) \
- while( ((Flu_File_Chooser::Entry*)array[right])->field < \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) right--
- #define CASE_QSCANL( field ) \
- while( casecompare( ((Flu_File_Chooser::Entry*)array[left])->field, \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) < 0 ) left++
- #define CASE_QSCANR( field ) \
- while( casecompare( ((Flu_File_Chooser::Entry*)array[right])->field, \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) > 0 ) right--
- #define CASE_RQSCANL( field ) \
- while( casecompare( ((Flu_File_Chooser::Entry*)array[left])->field, \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) > 0 ) left++
- #define CASE_RQSCANR( field ) \
- while( casecompare( ((Flu_File_Chooser::Entry*)array[right])->field, \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) < 0 ) right--
- #define CUSTOM_QSCANL( field ) \
- while( customSort( ((Flu_File_Chooser::Entry*)array[left])->field, \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) < 0 ) left++
- #define CUSTOM_QSCANR( field ) \
- while( customSort( ((Flu_File_Chooser::Entry*)array[right])->field, \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) > 0 ) right--
- #define CUSTOM_RQSCANL( field ) \
- while( customSort( ((Flu_File_Chooser::Entry*)array[left])->field, \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) > 0 ) left++
- #define CUSTOM_RQSCANR( field ) \
- while( customSort( ((Flu_File_Chooser::Entry*)array[right])->field, \
- ((Flu_File_Chooser::Entry*)array[pivot])->field ) < 0 ) right--
- void Flu_File_Chooser :: _qSort( int how, bool caseSort, Fl_Widget **array, int low, int high )
- {
- int left, right, pivot;
- Fl_Widget *temp;
- bool reverse = ( how & SORT_REVERSE );
- if( high > low )
- {
- left = low;
- right = high;
- pivot = low;
- while( right >= left )
- {
- switch( how & ~SORT_REVERSE )
- {
- case SORT_NAME:
- if( reverse )
- {
- if( customSort )
- {
- CUSTOM_RQSCANL( filename.c_str() );
- CUSTOM_RQSCANR( filename.c_str() );
- }
- else if( !caseSort )
- {
- CASE_RQSCANL( filename );
- CASE_RQSCANR( filename );
- }
- else
- {
- RQSCANL( filename );
- RQSCANR( filename );
- }
- }
- else
- {
- if( customSort )
- {
- CUSTOM_QSCANL( filename.c_str() );
- CUSTOM_QSCANR( filename.c_str() );
- }
- else if( !caseSort )
- {
- CASE_QSCANL( filename );
- CASE_QSCANR( filename );
- }
- else
- {
- QSCANL( filename );
- QSCANR( filename );
- }
- }
- break;
- case SORT_SIZE:
- if( reverse )
- {
- RQSCANL( isize );
- RQSCANR( isize );
- }
- else
- {
- QSCANL( isize );
- QSCANR( isize );
- }
- break;
- case SORT_DATE:
- if( reverse )
- {
- RQSCANL( idate );
- RQSCANR( idate );
- }
- else
- {
- QSCANL( idate );
- QSCANR( idate );
- }
- break;
- case SORT_TYPE:
- if( reverse )
- {
- RQSCANL( description );
- RQSCANR( description );
- }
- else
- {
- QSCANL( description );
- QSCANR( description );
- }
- break;
- }
- if( left > right )
- break;
- temp = array[left];
- array[left] = array[right];
- array[right] = temp;
- left++;
- right--;
- }
- _qSort( how, caseSort, array, low, right );
- _qSort( how, caseSort, array, left, high );
- }
- }
- Flu_File_Chooser :: FileList :: FileList( int x, int y, int w, int h, Flu_File_Chooser *c )
- : Flu_Wrap_Group( x, y, w, h )
- {
- chooser = c;
- numDirs = 0;
- }
- Flu_File_Chooser :: FileList :: ~FileList()
- {
- }
- void Flu_File_Chooser :: FileList :: sort( int n )
- {
- if( n != -1 )
- numDirs = n;
- if( children() == 0 )
- return;
- // the directories are already first. sort the directories then the names lexigraphically
- Flu_File_Chooser::_qSort( chooser->sortMethod, chooser->caseSort, (Fl_Widget**)array(), 0, numDirs-1 );
- Flu_File_Chooser::_qSort( chooser->sortMethod, chooser->caseSort, (Fl_Widget**)array(), numDirs, children()-1 );
- chooser->redraw();
- }
- int Flu_File_Chooser :: FileList :: handle( int event )
- {
- if( event == FL_FOCUS || event == FL_UNFOCUS )
- return 1;
- if( Flu_Wrap_Group::handle( event ) )
- return 1;
- // if push on no file, unselect all files and turn off editing mode
- if( event == FL_PUSH && !Fl::event_key( FL_SHIFT ) && !Fl::event_key( FL_CTRL ) )
- {
- chooser->unselect_all();
- chooser->filename.value( "" );
- chooser->filename.position( chooser->filename.size(), chooser->filename.size() );
- if( Fl::event_button3() )
- return chooser->popupContextMenu( NULL );
- return 1;
- }
- else if( event == FL_KEYDOWN )
- {
- if( Fl::event_key( FL_Delete ) )
- {
- // recycle by default, unless the shift key is held down
- chooser->trashCB( !Fl::event_state( FL_SHIFT ) );
- return 1;
- }
- Flu_File_Chooser::Entry *e = chooser->lastSelected;
- if( !e )
- {
- for( int i = 0; i < children(); i++ )
- if( ((Flu_File_Chooser::Entry*)child(i))->selected )
- {
- e = (Flu_File_Chooser::Entry*)child(i);
- break;
- }
- }
- if( e )
- {
- switch( Fl::event_key() )
- {
- case FL_Up: e = (Flu_File_Chooser::Entry*)previous( e );
- if( !e && children() ) e = (Flu_File_Chooser::Entry*)child(0); break;
- case FL_Down: e = (Flu_File_Chooser::Entry*)next( e );
- if( !e && children() ) e = (Flu_File_Chooser::Entry*)child(children()-1); break;
- case FL_Left: e = (Flu_File_Chooser::Entry*)left( e ); break;
- case FL_Right: e = (Flu_File_Chooser::Entry*)right( e ); break;
- case FL_Home: if( children() ) e = (Flu_File_Chooser::Entry*)child(0); break;
- case FL_End: if( children() ) e = (Flu_File_Chooser::Entry*)child(children()-1); break;
- case FL_Enter:
- chooser->filenameEnterCallback = true;
- //chooser->cd( e->filename.c_str() );
- chooser->okCB();
- return 1;
- case ' ':
- chooser->cd( e->filename.c_str() );
- return 1;
- default: e = 0; break;
- }
- if( e )
- {
- chooser->unselect_all();
- e->selected = true;
- chooser->lastSelected = e;
- chooser->filename.value( e->filename.c_str() );
- chooser->filename.position( chooser->filename.size(), chooser->filename.size() );
- chooser->redraw();
- if( e->type == ENTRY_FILE )
- chooser->previewGroup->file = chooser->currentDir + e->filename;
- scroll_to( e );
- return 1;
- }
- }
- }
- return 0;
- }
- Flu_File_Chooser :: FileDetails :: FileDetails( int x, int y, int w, int h, Flu_File_Chooser *c )
- : Fl_Pack( x, y, w, h )
- {
- chooser = c;
- numDirs = 0;
- }
- Flu_File_Chooser :: FileDetails :: ~FileDetails()
- {
- }
- void Flu_File_Chooser :: FileDetails :: scroll_to( Fl_Widget *w )
- {
- // we know all the widgets are the same height
- // so just find this widget and scroll to the accumulated height
- int H = 0;
- for( int i = 0; i < children(); i++ )
- {
- if( child(i) == w )
- {
- if( H > (int)chooser->filescroll->scrollbar.maximum() )
- H = (int)chooser->filescroll->scrollbar.maximum();
- chooser->filescroll->position( 0, H );
- return;
- }
- H += w->h();
- }
- }
- void Flu_File_Chooser :: FileDetails :: sort( int n )
- {
- if( n != -1 )
- numDirs = n;
- if( children() == 0 )
- return;
- // the directories are already first. sort the directories then the names lexigraphically
- Flu_File_Chooser::_qSort( chooser->sortMethod, chooser->caseSort, (Fl_Widget**)array(), 0, numDirs-1 );
- Flu_File_Chooser::_qSort( chooser->sortMethod, chooser->caseSort, (Fl_Widget**)array(), numDirs, children()-1 );
- chooser->redraw();
- }
- Fl_Widget* Flu_File_Chooser :: FileDetails :: next( Fl_Widget* w )
- {
- for( int i = 0; i < children()-1; i++ )
- {
- if( w == child(i) )
- return child(i+1);
- }
- return NULL;
- }
- Fl_Widget* Flu_File_Chooser :: FileDetails :: previous( Fl_Widget* w )
- {
- for( int i = 1; i < children(); i++ )
- {
- if( w == child(i) )
- return child(i-1);
- }
- return NULL;
- }
- int Flu_File_Chooser :: FileDetails :: handle( int event )
- {
- if( event == FL_FOCUS || event == FL_UNFOCUS )
- return 1;
- if( Fl_Pack::handle( event ) )
- return 1;
- else if( event == FL_PUSH )
- return 1;
- else if( event == FL_KEYDOWN )
- {
- if( Fl::event_key( FL_Delete ) )
- {
- // recycle by default, unless the shift key is held down
- chooser->trashCB( !Fl::event_state( FL_SHIFT ) );
- return 1;
- }
- Flu_File_Chooser::Entry *e = chooser->lastSelected;
- if( !e )
- {
- for( int i = 0; i < children(); i++ )
- if( ((Flu_File_Chooser::Entry*)child(i))->selected )
- {
- e = (Flu_File_Chooser::Entry*)child(i);
- break;
- }
- }
- if( e )
- {
- switch( Fl::event_key() )
- {
- case FL_Up: e = (Flu_File_Chooser::Entry*)previous( e );
- if( !e && children() ) e = (Flu_File_Chooser::Entry*)child(0); break;
- case FL_Down: e = (Flu_File_Chooser::Entry*)next( e );
- if( !e && children() ) e = (Flu_File_Chooser::Entry*)child(children()-1); break;
- case FL_Home: if( children() ) e = (Flu_File_Chooser::Entry*)child(0); break;
- case FL_End: if( children() ) e = (Flu_File_Chooser::Entry*)child(children()-1); break;
- case FL_Enter:
- chooser->filenameEnterCallback = true;
- //chooser->cd( e->filename.c_str() );
- chooser->okCB();
- return 1;
- case ' ':
- chooser->cd( e->filename.c_str() );
- return 1;
- default: e = 0; break;
- }
- if( e )
- {
- chooser->unselect_all();
- e->selected = true;
- chooser->lastSelected = e;
- chooser->filename.value( e->filename.c_str() );
- chooser->filename.position( chooser->filename.size(), chooser->filename.size() );
- chooser->redraw();
- scroll_to( e );
- return 1;
- }
- }
- }
- return 0;
- }
- Flu_File_Chooser :: Entry :: Entry( const char* name, int t, bool d, Flu_File_Chooser *c )
- : Fl_Input( 0, 0, 0, 0 )
- {
- resize( 0, 0, DEFAULT_ENTRY_WIDTH, 20 );
- textsize( 12 );
- box( FL_BORDER_BOX );
- when( FL_WHEN_RELEASE_ALWAYS | FL_WHEN_ENTER_KEY_ALWAYS );
- callback( _inputCB, this );
- filename = name;
- selected = false;
- chooser = c;
- details = d;
- type = t;
- icon = NULL;
- editMode = 0;
- description = "";
- if( type == ENTRY_FILE && (c->selectionType & DEACTIVATE_FILES) )
- {
- textcolor( FL_GRAY );
- deactivate();
- }
- updateSize();
- updateIcon();
- }
- void Flu_File_Chooser :: Entry :: updateIcon()
- {
- Flu_File_Chooser::FileTypeInfo *tt = NULL;
- if( type==ENTRY_MYCOMPUTER )
- {
- icon = &computer;
- description = myComputerTxt;
- }
- else if( type==ENTRY_MYDOCUMENTS )
- {
- icon = &documents;
- description = myDocumentsTxt;
- }
- else if( type==ENTRY_DRIVE )
- {
- //icon = &disk_drive;
- //description = "";
- }
- else if( type==ENTRY_DIR || type==ENTRY_FAVORITE )
- tt = Flu_File_Chooser::find_type( NULL );
- else
- {
- const char *dot = strrchr( filename.c_str(), '.' );
- if( dot )
- {
- tt = Flu_File_Chooser::find_type( dot+1 );
- if( !tt )
- description = dot+1;
- }
- }
- if( tt )
- {
- icon = tt->icon;
- description = tt->type;
- }
- // if there is no icon, assign a default one
- if( !icon && type==ENTRY_FILE && !(chooser->selectionType & DEACTIVATE_FILES) )
- icon = chooser->defaultFileIcon;
- if( type==ENTRY_FAVORITE )
- icon = &little_favorites;
- toolTip = detailTxt[0] + ": " + filename;
- if( type == ENTRY_FILE )
- toolTip += "\n" + detailTxt[1] +": " + filesize;
- toolTip += "\n" + detailTxt[3] + ": " + description;
- tooltip( toolTip.c_str() );
- redraw();
- }
- void Flu_File_Chooser :: resize( int x, int y, int w, int h )
- {
- Fl_Double_Window::resize( x, y, w, h );
- if( fileListWideBtn->value() )
- filelist->scrollbar.linesize( filelist->w() );
- else if( fileListBtn->value() )
- filelist->scrollbar.linesize( DEFAULT_ENTRY_WIDTH+4 );
- // round position to nearest multiple of the linesize
- ((Fl_Valuator*)&(filelist->scrollbar))->value( filelist->w()*(filelist->scrollbar.value()/filelist->w()) );
- for( int i = 0; i < filelist->children(); i++ )
- ((Entry*)filelist->child(i))->updateSize();
- }
- void Flu_File_Chooser :: listModeCB()
- {
- bool listMode = !fileDetailsBtn->value() || ( currentDir == FAVORITES_UNIQUE_STRING );
- if( listMode )
- {
- while( filedetails->children() )
- filelist->add( filedetails->child(0) );
- }
- else
- {
- while( filelist->children() )
- filedetails->add( filelist->child(0) );
- }
- resize( x(), y(), w(), h() );
- updateEntrySizes();
- if( listMode )
- {
- fileDetailsGroup->hide();
- filelist->show();
- filelist->redraw();
- filelist->parent()->resizable( filelist );
- }
- else
- {
- filelist->hide();
- fileDetailsGroup->show();
- fileDetailsGroup->parent()->resizable( fileDetailsGroup );
- }
- //redraw();
- }
- void Flu_File_Chooser :: Entry :: updateSize()
- {
- if( type==ENTRY_FAVORITE || chooser->fileListWideBtn->value() )
- {
- resize( x(), y(), chooser->filelist->w()-4, 20 );
- }
- else
- resize( x(), y(), DEFAULT_ENTRY_WIDTH, 20 );
- details = chooser->fileDetailsBtn->value() && ( type != ENTRY_FAVORITE );
- if( details )
- {
- nameW = chooser->detailNameBtn->w();
- typeW = chooser->detailTypeBtn->w();
- sizeW = chooser->detailSizeBtn->w();
- dateW = chooser->detailDateBtn->w();
- resize( x(), y(), chooser->filedetails->w(), 20 );
- }
- else
- nameW = w();
- // how big is the icon?
- int iW = 0, iH = 0;
- if( icon )
- {
- iW = icon->w()+2;
- iH = icon->h();
- }
- fl_font( textfont(), textsize() );
- // measure the name and see if we need a truncated version
- int W = 0, H = 0;
- fl_measure( filename.c_str(), W, H );
- if( W > nameW-iW )
- {
- // progressively strip characters off the end of the name until
- // it fits with "..." at the end
- if( altname[0] != '\0' )
- shortname = altname;
- else
- shortname = filename;
- int len = shortname.size();
- while( W > (nameW-iW) && len > 3 )
- {
- shortname[len-3] = '.';
- shortname[len-2] = '.';
- shortname[len-1] = '.';
- shortname[len] = '\0';
- len--;
- W = 0;
- fl_measure( shortname.c_str(), W, H );
- }
- }
- else
- shortname = "";
- // measure the description and see if we need a truncated version
- shortDescription = "";
- if( details )
- {
- W = 0; H = 0;
- fl_measure( description.c_str(), W, H );
- if( W > typeW-4 )
- {
- // progressively strip characters off the end of the description until
- // it fits with "..." at the end
- shortDescription = description;
- int len = shortDescription.size();
- while( W > typeW-4 && len > 3 )
- {
- shortDescription[len-3] = '.';
- shortDescription[len-2] = '.';
- shortDescription[len-1] = '.';
- shortDescription[len] = '\0';
- len--;
- W = 0;
- fl_measure( shortDescription.c_str(), W, H );
- }
- }
- }
- redraw();
- }
- Flu_File_Chooser :: Entry :: ~Entry()
- {
- }
- void Flu_File_Chooser :: Entry :: inputCB()
- {
- redraw();
- // if the user tried to change the string to nothing, restore the original name and turn off edit mode
- if( strlen( value() ) == 0 )
- {
- editMode = 0;
- return;
- }
- // if input text is different from filename, try to change the filename
- if( strcmp( value(), filename.c_str() ) != 0 )
- {
- // build the total old filename and new filename
- FluSimpleString oldName = chooser->currentDir + filename,
- newName = chooser->currentDir + value();
- // see if new name already exists
- struct stat s;
- int result = ::stat( newName.c_str(), &s );
- if( result == 0 )
- {
- fl_alert( fileExistsErrTxt.c_str(), newName.c_str() );
- return; // leave editing on
- }
- if( rename( oldName.c_str(), newName.c_str() ) == -1 )
- {
- fl_alert( renameErrTxt.c_str(), oldName.c_str(), newName.c_str() );
- //return; // leave editing on
- }
- else
- {
- filename = value();
- updateSize();
- updateIcon();
- }
- // QUESTION: should we set the chooser filename to the modified name?
- //chooser->filename.value( filename.c_str() );
- }
- // only turn off editing if we have a successful name change
- editMode = 0;
- }
- Fl_Group* Flu_File_Chooser :: getEntryGroup()
- {
- return (!fileDetailsBtn->value() || currentDir == FAVORITES_UNIQUE_STRING ) ? &(filelist->group) : filedetails;
- }
- Fl_Group* Flu_File_Chooser :: getEntryContainer()
- {
- return (!fileDetailsBtn->value() || currentDir == FAVORITES_UNIQUE_STRING ) ? (Fl_Group*)filelist : filedetails;
- }
- int Flu_File_Chooser :: Entry :: handle( int event )
- {
- if( editMode )
- {
- // if user hits 'Escape' while in edit mode, restore the original name and turn off edit mode
- if( event == FL_KEYDOWN && Fl::event_key( FL_Escape ) )
- {
- editMode = 0;
- redraw();
- if( selected )
- chooser->trashBtn->activate();
- return 1;
- }
- return Fl_Input::handle( event );
- }
- if( event == FL_FOCUS || event == FL_UNFOCUS )
- return 1;
- if( event == FL_ENTER || event == FL_LEAVE )
- return 1;
- Fl_Group *g = chooser->getEntryGroup();
- if( event == FL_PUSH )
- {
- if( Fl::event_clicks() > 0 )
- {
- Fl::event_clicks(0);
- // double-clicking a favorite cd's to it
- if( type == ENTRY_FAVORITE )
- {
- chooser->delay_cd( filename );
- }
- // double-clicking a directory cd's to it
- else if( type != ENTRY_FILE )
- {
- #ifdef WIN32
- if( filename[1] == ':' )
- chooser->delay_cd( filename );
- else
- #endif
- chooser->delay_cd( chooser->currentDir + filename + "/" );
- }
- // double-clicking a file chooses it if we are in file selection mode
- else if( !(chooser->selectionType & DIRECTORY) || (chooser->selectionType & STDFILE) )
- {
- Fl::add_timeout( 0.0f, Flu_File_Chooser::selectCB, chooser );
- }
- if( selected )
- chooser->trashBtn->activate();
- return 1;
- }
- /*
- if( selected && !Fl::event_button3() && !Fl::event_state(FL_CTRL) && !Fl::event_state(FL_SHIFT) )
- {
- // only allow editing of certain files and directories
- if( chooser->fileEditing && ( type == ENTRY_FILE || type == ENTRY_DIR ) )
- {
- // if already selected, switch to input mode
- Fl::add_timeout( 1.0, _editCB, this );
- return 1;
- }
- }
- else*/
- if( chooser->selectionType & MULTI )
- {
- if( Fl::event_state(FL_CTRL) )
- {
- selected = !selected; // toggle this item
- chooser->lastSelected = this;
- if( type == ENTRY_FILE )
- chooser->previewGroup->file = chooser->currentDir + filename;
- chooser->redraw();
- chooser->getEntryContainer()->take_focus();
- }
- else if( Fl::event_state(FL_SHIFT) )
- {
- // toggle all items from the last selected item to this one
- if( chooser->lastSelected == NULL )
- {
- selected = true;
- chooser->lastSelected = this;
- if( type == ENTRY_FILE )
- chooser->previewGroup->file = chooser->currentDir + filename;
- chooser->redraw();
- chooser->getEntryContainer()->take_focus();
- }
- else
- {
- // get the index of the last selected item and this item
- int lastindex = -1, thisindex = -1;
- int i;
- for( i = 0; i < g->children(); i++ )
- {
- if( g->child(i) == chooser->lastSelected )
- lastindex = i;
- if( g->child(i) == this )
- thisindex = i;
- if( lastindex >= 0 && thisindex >= 0 )
- break;
- }
- if( lastindex >= 0 && thisindex >= 0 )
- {
- // loop from this item to the last item, toggling each item except the last
- int inc;
- if( thisindex > lastindex )
- inc = -1;
- else
- inc = 1;
- Entry *e;
- for( i = thisindex; i != lastindex; i += inc )
- {
- e = (Entry*)g->child(i);
- e->selected = !e->selected;
- e->redraw();
- }
- chooser->lastSelected = this;
- if( type == ENTRY_FILE )
- chooser->previewGroup->file = chooser->currentDir + filename;
- chooser->redraw();
- chooser->getEntryContainer()->take_focus();
- }
- }
- }
- else
- {
- chooser->unselect_all();
- selected = true;
- chooser->lastSelected = this;
- if( type == ENTRY_FILE )
- chooser->previewGroup->file = chooser->currentDir + filename;
- chooser->redraw();
- chooser->getEntryContainer()->take_focus();
- }
- if( !((chooser->selectionType & Flu_File_Chooser::DIRECTORY) ||
- (chooser->selectionType & Flu_File_Chooser::STDFILE)) &&
- ( Fl::event_state(FL_CTRL) || Fl::event_state(FL_SHIFT) ) )
- {
- // if we are only choosing multiple files, don't allow a directory
- // to be selected
- Fl_Group *g = chooser->getEntryGroup();
- for( int i = 0; i < g->children(); i++ )
- {
- Entry *e = (Entry*)g->child(i);
- if( e->type == ENTRY_DIR )
- e->selected = false;
- }
- }
- }
- else
- {
- chooser->unselect_all();
- selected = true;
- chooser->lastSelected = this;
- if( type == ENTRY_FILE )
- chooser->previewGroup->file = chooser->currentDir + filename;
- chooser->redraw();
- chooser->getEntryContainer()->take_focus();
- }
- //g->take_focus();
- redraw();
- if( selected )
- chooser->trashBtn->activate();
- if( Fl::event_button3() )
- return chooser->popupContextMenu( this );
- // don't put the filename into the box if we are a directory but we are not choosing directories
- // or if we are in SAVING mode
- if( (chooser->selectionType & Flu_File_Chooser::DIRECTORY) ||
- (chooser->selectionType & Flu_File_Chooser::STDFILE) ||
- type==ENTRY_FILE )
- chooser->filename.value( filename.c_str() );
- else if( !(chooser->selectionType & Flu_File_Chooser::SAVING ) )
- chooser->filename.value( "" );
- chooser->filename.position( chooser->filename.size(), chooser->filename.size() );
- return 1;
- }
- else if( event == FL_DRAG )
- {
- if( chooser->selectionType & MULTI )
- {
- // toggle all items from the last selected item to this one
- if( chooser->lastSelected != NULL )
- {
- selected = true;
- // get the index of the last selected item and this item
- int lastindex = -1, thisindex = -1;
- int i;
- for( i = 0; i < g->children(); i++ )
- {
- if( g->child(i) == chooser->lastSelected )
- lastindex = i;
- if( g->child(i) == this )
- thisindex = i;
- if( lastindex >= 0 && thisindex >= 0 )
- break;
- }
- if( lastindex >= 0 && thisindex >= 0 )
- {
- // loop from this item to the last item, toggling each item except the last
- int inc;
- if( thisindex > lastindex )
- inc = -1;
- else
- inc = 1;
- Entry *e;
- for( i = thisindex; i != lastindex; i += inc )
- {
- e = (Entry*)g->child(i);
- e->selected = !e->selected;
- e->redraw();
- }
- chooser->lastSelected = this;
- if( type == ENTRY_FILE )
- chooser->previewGroup->file = chooser->currentDir + filename;
- chooser->redraw();
- }
- redraw();
- chooser->getEntryContainer()->take_focus();
- if( selected )
- chooser->trashBtn->activate();
- return 1;
- }
- }
- }
- return Fl_Widget::handle(event);
- }
- void Flu_File_Chooser :: Entry :: editCB()
- {
- // if already selected, switch to input mode
- editMode = 2;
- value( filename.c_str() );
- take_focus();
- // select the text up to but not including the extension
- const char *dot = strrchr( filename.c_str(), '.' );
- if( dot )
- position( 0, dot-filename.c_str() );
- else
- position( 0, filename.size() );
- chooser->trashBtn->deactivate();
- redraw();
- }
- int Flu_File_Chooser :: popupContextMenu( Entry *entry )
- {
- int type = entry ? entry->type : ENTRY_NONE;
- char *filename = entry ? (char*)entry->filename.c_str() : NULL;
- char *ext = NULL;
- if( filename )
- ext = strrchr( filename, '.' );
- if( ext )
- {
- ext = strdup( ext+1 ); // skip the '.'
- for( unsigned int i = 0; i < strlen(ext); i++ )
- ext[i] = tolower( ext[i] );
- }
- enum { ACTION_NEW_FOLDER = -1, ACTION_RENAME = -2, ACTION_DELETE = -3 };
- entryPopup.clear();
- switch( type )
- {
- case ENTRY_NONE: // right click on nothing
- entryPopup.add( contextMenuTxt[0].c_str(), 0, 0, (void*)ACTION_NEW_FOLDER );
- break;
- case ENTRY_DIR:
- entryPopup.add( contextMenuTxt[1].c_str(), 0, 0, (void*)ACTION_RENAME );
- entryPopup.add( contextMenuTxt[2].c_str(), 0, 0, (void*)ACTION_DELETE );
- break;
- case ENTRY_FILE:
- entryPopup.add( contextMenuTxt[1].c_str(), 0, 0, (void*)ACTION_RENAME );
- entryPopup.add( contextMenuTxt[2].c_str(), 0, 0, (void*)ACTION_DELETE );
- break;
- case ENTRY_FAVORITE:
- entryPopup.add( contextMenuTxt[2].c_str(), 0, 0, (void*)ACTION_DELETE );
- break;
- case ENTRY_DRIVE:
- break;
- case ENTRY_MYDOCUMENTS:
- break;
- case ENTRY_MYCOMPUTER:
- break;
- }
- // add the programmable context handlers
- for( unsigned int i = 0; i < contextHandlers.size(); i++ )
- {
- if( !(contextHandlers[i].type & type) )
- continue;
- if( type == ENTRY_FILE )
- if( contextHandlers[i].ext.size() && contextHandlers[i].ext != ext )
- continue;
- entryPopup.add( contextHandlers[i].name.c_str(), 0, 0, (void*)i );
- }
- if( ext )
- free( ext );
- entryPopup.position( Fl::event_x(), Fl::event_y() );
- const Fl_Menu_Item *selection = entryPopup.popup();
- if( selection )
- {
- int handler = (int)selection->user_data();
- switch( handler )
- {
- case ACTION_NEW_FOLDER:
- newFolderCB();
- break;
- case ACTION_RENAME:
- entry->editCB();
- /*
- entry->editMode = 2;
- entry->value( entry->filename.c_str() );
- entry->take_focus();
- entry->position( 0, entry->filename.size() );
- trashBtn->deactivate();
- */
- break;
- case ACTION_DELETE:
- // recycle by default, unless the shift key is held down
- trashCB( !Fl::event_state( FL_SHIFT ) );
- break;
- default:
- contextHandlers[handler].callback( filename, type, contextHandlers[handler].callbackData );
- break;
- }
- }
- else
- return handle( FL_PUSH );
- return 1;
- }
- void Flu_File_Chooser :: Entry :: draw()
- {
- if( editMode )
- {
- if( editMode == 2 )
- {
- editMode--;
- fl_draw_box( FL_FLAT_BOX, x(), y(), w(), h(), FL_WHITE );
- redraw();
- }
- Fl_Input::draw();
- return;
- }
- if( selected )
- {
- fl_draw_box( FL_FLAT_BOX, x(), y(), w(), h(), FL_SELECTION_COLOR );
- fl_color( FL_WHITE );
- }
- else
- {
- fl_draw_box( FL_FLAT_BOX, x(), y(), w(), h(), FL_WHITE );
- fl_color( FL_BLACK );
- }
- int X = x()+4;
- if( icon )
- {
- icon->draw( X, y()+h()/2-icon->h()/2 );
- X += icon->w()+2;
- }
- fl_font( textfont(), textsize() );
- //fl_color( textcolor() );
- if( shortname[0] != '\0' )
- fl_draw( shortname.c_str(), X, y(), nameW, h(), FL_ALIGN_LEFT );
- else if( altname[0] != '\0' )
- fl_draw( altname.c_str(), X, y(), nameW, h(), FL_ALIGN_LEFT );
- else
- fl_draw( filename.c_str(), X, y(), nameW, h(), FL_ALIGN_LEFT );
- X = x()+4 + nameW;
- if( details )
- {
- if( shortDescription[0] != '\0' )
- fl_draw( shortDescription.c_str(), X, y(), typeW-4, h(), Fl_Align(FL_ALIGN_LEFT | FL_ALIGN_CLIP) );
- else
- fl_draw( description.c_str(), X, y(), typeW-4, h(), Fl_Align(FL_ALIGN_LEFT | FL_ALIGN_CLIP) );
- X += typeW;
- fl_draw( filesize.c_str(), X, y(), sizeW-4, h(), Fl_Align(FL_ALIGN_RIGHT | FL_ALIGN_CLIP) );
- X += sizeW+4;
- fl_draw( date.c_str(), X, y(), dateW-4, h(), Fl_Align(FL_ALIGN_LEFT | FL_ALIGN_CLIP) );
- }
- }
- void Flu_File_Chooser :: unselect_all()
- {
- Fl_Group *g = getEntryGroup();
- Entry *e;
- for( int i = 0; i < g->children(); i++ )
- {
- e = ((Entry*)g->child(i));
- e->selected = false;
- e->editMode = 0;
- }
- lastSelected = 0;
- previewGroup->file = "";
- previewGroup->redraw();
- trashBtn->deactivate();
- redraw();
- }
- void Flu_File_Chooser :: select_all()
- {
- if( !( selectionType & MULTI ) )
- return;
- Fl_Group *g = getEntryGroup();
- Entry *e;
- previewGroup->file = "";
- for( int i = 0; i < g->children(); i++ )
- {
- e = ((Entry*)g->child(i));
- e->selected = true;
- e->editMode = 0;
- previewGroup->file = e->filename;
- filename.value( e->filename.c_str() );
- }
- lastSelected = 0;
- previewGroup->redraw();
- trashBtn->deactivate();
- redraw();
- }
- void Flu_File_Chooser :: updateEntrySizes()
- {
- filecolumns->W1 = detailNameBtn->w();
- filecolumns->W2 = detailTypeBtn->w();
- filecolumns->W3 = detailSizeBtn->w();
- filecolumns->W4 = detailDateBtn->w();
- // update the size of each entry because the user changed the size of each column
- filedetails->resize( filedetails->x(), filedetails->y(), filescroll->w(), filedetails->h() );
- int i;
- for( i = 0; i < filedetails->children(); i++ )
- ((Entry*)filedetails->child(i))->updateSize();
- for( i = 0; i < filelist->children(); i++ )
- ((Entry*)filelist->child(i))->updateSize();
- }
- const char* Flu_File_Chooser :: value()
- {
- if( filename.size() == 0 )
- return NULL;
- else
- {
- #ifdef WIN32
- // on windows, be sure the drive letter is lowercase for
- // compatibility with fl_filename_relative()
- if( filename.size() > 1 && filename.value()[1] == ':' )
- ((char*)(filename.value()))[0] = tolower( filename.value()[0] );
- #endif
- return filename.value();
- }
- }
- int Flu_File_Chooser :: count()
- {
- if( selectionType & MULTI )
- {
- int n = 0;
- Fl_Group *g = getEntryGroup();
- for( int i = 0; i < g->children(); i++ )
- {
- #ifdef WIN32
- if( ((Entry*)g->child(i))->filename == myComputerTxt )
- continue;
- #endif
- if( ((Entry*)g->child(i))->selected )
- n++;
- }
- return n;
- }
- else
- return (strlen(filename.value())==0)? 0 : 1;
- }
- void Flu_File_Chooser :: value( const char *v )
- {
- cd( v );
- if( !v )
- return;
- // try to find the file and select it
- const char *slash = strrchr( v, '/' );
- if( slash )
- slash++;
- else
- {
- slash = strrchr( v, '\\' );
- if( slash )
- slash++;
- else
- slash = v;
- }
- filename.value( slash );
- filename.position( filename.size(), filename.size() );
- Fl_Group *g = getEntryGroup();
- for( int i = 0; i < g->children(); i++ )
- {
- if( ((Entry*)g->child(i))->filename == slash )
- {
- ((Entry*)g->child(i))->selected = true;
- filelist->scroll_to( (Entry*)g->child(i) );
- filedetails->scroll_to( (Entry*)g->child(i) );
- redraw();
- return;
- }
- }
- }
- const char* Flu_File_Chooser :: value( int n )
- {
- Fl_Group *g = getEntryGroup();
- for( int i = 0; i < g->children(); i++ )
- {
- #ifdef WIN32
- if( ((Entry*)g->child(i))->filename == myComputerTxt )
- continue;
- #endif
- if( ((Entry*)g->child(i))->selected )
- {
- n--;
- if( n == 0 )
- {
- FluSimpleString s = currentDir + ((Entry*)g->child(i))->filename;
- filename.value( s.c_str() );
- filename.position( filename.size(), filename.size() );
- return value();
- }
- }
- }
- return "";
- }
- void Flu_File_Chooser :: reloadCB()
- {
- #ifdef WIN32
- refreshDrives = true;
- #endif
- cd( currentDir.c_str() );
- }
- void Flu_File_Chooser :: addToFavoritesCB()
- {
- // eliminate duplicates
- bool duplicate = false;
- for( int i = 1; i <= favoritesList->size(); i++ )
- {
- if( streq( currentDir.c_str(), favoritesList->text(i) ) )
- {
- duplicate = true;
- break;
- }
- }
- if( !duplicate )
- favoritesList->add( currentDir.c_str() );
- // save the favorites
- FILE *f = fopen( configFilename.c_str(), "w" );
- if( f )
- {
- for( int i = 1; i <= favoritesList->size(); i++ )
- fprintf( f, "%s\n", favoritesList->text(i) );
- fclose( f );
- }
- }
- FluSimpleString Flu_File_Chooser :: formatDate( const char *d )
- {
- if( d == 0 )
- {
- FluSimpleString s;
- return s;
- }
- // convert style "Wed Mar 19 07:23:11 2003" to "MM/DD/YY HH:MM AM|PM"
- int month, day, year, hour, minute, second;
- bool pm;
- char MM[16], dummy[64];
- sscanf( d, "%s %s %d %d:%d:%d %d", dummy, MM, &day, &hour, &minute, &second, &year );
- pm = ( hour >= 12 );
- if( hour == 0 )
- hour = 12;
- if( hour >= 13 )
- hour -= 12;
- if( strcmp(MM,"Jan")==0 ) month = 1;
- else if( strcmp(MM,"Feb")==0 ) month = 2;
- else if( strcmp(MM,"Mar")==0 ) month = 3;
- else if( strcmp(MM,"Apr")==0 ) month = 4;
- else if( strcmp(MM,"May")==0 ) month = 5;
- else if( strcmp(MM,"Jun")==0 ) month = 6;
- else if( strcmp(MM,"Jul")==0 ) month = 7;
- else if( strcmp(MM,"Aug")==0 ) month = 8;
- else if( strcmp(MM,"Sep")==0 ) month = 9;
- else if( strcmp(MM,"Oct")==0 ) month = 10;
- else if( strcmp(MM,"Nov")==0 ) month = 11;
- else month = 12;
- sprintf( dummy, "%d/%d/%02d %d:%02d %s", month, day, year, hour, minute, pm?"PM":"AM" );
- FluSimpleString formatted = dummy;
- return formatted;
- }
- void Flu_File_Chooser :: win2unix( FluSimpleString &s )
- {
- int len = s.size();
- for( int i = 0; i < len; i++ )
- if( s[i] == '\\' )
- s[i] = '/';
- }
- void Flu_File_Chooser :: cleanupPath( FluSimpleString &s )
- {
- // convert all '\' to '/'
- win2unix( s );
- FluSimpleString newS(s.size()+1);
- int oldPos, newPos;
- for( oldPos = 0, newPos = 0; oldPos < s.size(); oldPos++ )
- {
- // remove "./"
- if( s[oldPos] == '.' && s[oldPos+1] == '/' )
- oldPos += 2;
- // convert "//" to "/"
- else if( s[oldPos] == '/' && s[oldPos+1] == '/' )
- oldPos++;
- #ifdef WIN32
- // convert "c:" to "C:"
- else if( s[oldPos+1] == ':' )
- s[oldPos] = toupper( s[oldPos] );
- #endif
- // remove "../" by removing everything back to the last "/"
- if( oldPos+2 < s.size() ) // bounds check
- {
- if( s[oldPos] == '.' && s[oldPos+1] == '.' && s[oldPos+2] == '/' && newS != "/" )
- {
- // erase the last character, which should be a '/'
- newPos--;
- newS[newPos] = '\0';
- // look for the previous '/'
- const char *lastSlash = strrchr( newS.c_str(), '/' );
- // make the new string position after the slash
- newPos = (lastSlash-newS.c_str())+1;
- oldPos += 3;
- }
- }
- newS[newPos] = s[oldPos];
- newPos++;
- }
- newS[newPos] = '\0';
- s = newS;
- }
- void Flu_File_Chooser :: delay_cd( FluSimpleString path )
- {
- delayedCd = path;
- Fl::add_timeout( 0.0f, Flu_File_Chooser::delayedCdCB, this );
- }
- void Flu_File_Chooser :: backCB()
- {
- if( !currentHist ) return;
- if( currentHist->last )
- {
- currentHist = currentHist->last;
- walkingHistory = true;
- delay_cd( currentHist->path );
- }
- }
- void Flu_File_Chooser :: forwardCB()
- {
- if( !currentHist ) return;
- if( currentHist->next )
- {
- currentHist = currentHist->next;
- walkingHistory = true;
- delay_cd( currentHist->path );
- }
- }
- bool Flu_File_Chooser :: correctPath( FluSimpleString &path )
- {
- // the path may or may not be an alias, needing corrected
- #ifdef WIN32
- // point to the correct desktop
- if( path == "/"+desktopTxt+"/" )
- {
- path = userDesktop;
- return true;
- }
- else if( path == userDesktop )
- return true;
- else if( path == "/"+desktopTxt+"/"+myComputerTxt+"/" ||
- path == userDesktop+myComputerTxt+"/" )
- path = "/";
- else if( path == "/"+desktopTxt+"/"+myDocumentsTxt+"/" ||
- path == userDesktop+myDocumentsTxt+"/" )
- path = userDocs;
- #endif
- return false;
- }
- void Flu_File_Chooser :: locationCB( const char *path )
- {
- #ifdef WIN32
- FluSimpleString p = path;
- if( p == "/"+favoritesTxt+"/" )
- favoritesCB();
- else if( p == "/"+desktopTxt+"/"+myComputerTxt+"/" )
- myComputerCB();
- else if( p == "/"+desktopTxt+"/"+myDocumentsTxt+"/" )
- documentsCB();
- else if( p == "/"+desktopTxt+"/" )
- desktopCB();
- // if the path leads off with "/Desktop/My Computer", then strip that part off and cd
- // to the remaining
- else
- {
- FluSimpleString s = "/"+desktopTxt+"/"+myComputerTxt+"/";
- if( strstr( path, s.c_str() ) == path )
- {
- // seach for '(' and if present, extract the drive name and cd to it
- char *paren = strrchr( path, '(' );
- if( paren )
- {
- char drive[] = "A:/";
- drive[0] = toupper(paren[1]);
- cd( drive );
- }
- else
- {
- cd( path+21 );
- }
- }
- }
- #else
- cd( path );
- #endif
- updateLocationQJ();
- }
- void Flu_File_Chooser :: buildLocationCombo()
- {
- // add all filesystems
- location->tree.clear();
- #ifdef WIN32
- FluSimpleString s;
- char volumeName[1024];
- Flu_Tree_Browser::Node *n;
- s = "/"+desktopTxt+"/";
- n = location->tree.add( s.c_str() ); n->branch_icon( &little_desktop );
- s = "/"+desktopTxt+"/"+myDocumentsTxt+"/";
- n = location->tree.add( s.c_str() ); n->branch_icon( &documents );
- s = "/"+desktopTxt+"/"+myComputerTxt+"/";
- n = location->tree.add( s.c_str() ); n->branch_icon( &computer );
- // get the location and add them
- {
- if( refreshDrives )
- driveMask = GetLogicalDrives();
- DWORD mask = driveMask;
- for( int i = 0; i < 26; i++ )
- {
- drives[i] = "";
- driveIcons[i] = &disk_drive;
- if( mask & 1 )
- {
- s = "/"+desktopTxt+"/"+myComputerTxt+"/";
- char drive[] = "A:";
- char windrive[] = "A:\\";
- windrive[0] = drive[0] = 'A' + i;
- DWORD type;
- if( refreshDrives )
- {
- volumeName[0] = '\0';
- type = driveTypes[i] = GetDriveType( windrive );
- if( type != DRIVE_REMOVABLE && type != DRIVE_REMOTE )
- GetVolumeInformation( windrive, volumeName, 1024, NULL, NULL, NULL, NULL, 0 );
- volumeNames[i] = volumeName;
- }
- else
- {
- strncpy( volumeName, volumeNames[i].c_str(), 1024 );
- type = driveTypes[i];
- }
- //s += volume
- const char *disk = "Disk";
- switch( type )
- {
- case DRIVE_REMOVABLE:
- disk = strlen(volumeName)?volumeName: ( 1 < 2 ? diskTypesTxt[0].c_str() : diskTypesTxt[1].c_str() );
- driveIcons[i] = &floppy_drive;
- break;
- case DRIVE_FIXED:
- disk = strlen(volumeName)?volumeName:diskTypesTxt[2].c_str();
- //driveIcons[i] = &disk_drive;
- break;
- case DRIVE_CDROM:
- disk = strlen(volumeName)?volumeName:diskTypesTxt[3].c_str();
- driveIcons[i] = &cd_drive;
- break;
- case DRIVE_REMOTE:
- disk = strlen(volumeName)?volumeName:diskTypesTxt[4].c_str();
- driveIcons[i] = &network_drive;
- break;
- case DRIVE_RAMDISK:
- disk = strlen(volumeName)?volumeName:diskTypesTxt[5].c_str();
- driveIcons[i] = &ram_drive;
- break;
- }
- drives[i] = FluSimpleString(disk) + " (" + FluSimpleString(drive) + ")/";
- s += drives[i];
- n = location->tree.add( s.c_str() ); n->branch_icon( driveIcons[i] );
- // erase the trailing '/' to make things look nicer
- drives[i][ drives[i].size()-1 ] = '\0';
- }
- mask >>= 1;
- }
- }
- s = favoritesTxt+"/";
- n = location->tree.add( s.c_str() ); n->branch_icon( &little_favorites );
- refreshDrives = false;
- #elif defined __APPLE__
- location->tree.label( "/" );
- // get all volume mount points and add to the location combobox
- dirent **e;
- char *name;
- int num = fl_filename_list( "/Volumes/", &e );
- if( num > 0 )
- {
- int i;
- for( i = 0; i < num; i++ )
- {
- name = e[i]->d_name;
- // ignore the "." and ".." names
- if( strcmp( name, "." ) == 0 || strcmp( name, ".." ) == 0 ||
- strcmp( name, "./" ) == 0 || strcmp( name, "../" ) == 0 ||
- strcmp( name, ".\\" ) == 0 || strcmp( name, "..\\" ) == 0 )
- continue;
- // if 'name' ends in '/', remove it
- if( name[strlen(name)-1] == '/' )
- name[strlen(name)-1] = '\0';
- FluSimpleString fullpath = "/Volumes/";
- fullpath += name;
- fullpath += "/";
- location->tree.add( fullpath.c_str() );
- }
- }
- #else
- location->tree.label( "/" );
- // get all mount points and add to the location combobox
- FILE *fstab; // /etc/mtab or /etc/mnttab file
- char dummy[256], mountPoint[256], line[1024]; // Input line
- FluSimpleString mount;
- fstab = fopen( "/etc/fstab", "r" ); // Otherwise fallback to full list
- if( fstab )
- {
- while( fgets( line, 1024, fstab ) )
- {
- if( line[0] == '#' || line[0] == '\n' )
- continue;
- // in fstab, mount point is second full string
- sscanf( line, "%s %s", dummy, mountPoint );
- mount = mountPoint;
- // cull some stuff
- if( mount[0] != '/' ) continue;
- if( mount == "/" ) continue;
- if( mount == "/boot" ) continue;
- if( mount == "/proc" ) continue;
- // now add the mount point
- mount += "/";
- location->tree.add( mount.c_str() );
- }
- fclose( fstab );
- }
- #endif
- }
- void Flu_File_Chooser :: clear_history()
- {
- currentHist = history;
- while( currentHist )
- {
- History *next = currentHist->next;
- delete currentHist;
- currentHist = next;
- }
- currentHist = history = NULL;
- backBtn->deactivate();
- forwardBtn->deactivate();
- }
- void Flu_File_Chooser :: addToHistory()
- {
- // remember history
- // only store this path in the history if it is not the current directory
- if( currentDir.size() && !walkingHistory )
- {
- if( history == NULL )
- {
- history = new History;
- currentHist = history;
- currentHist->path = currentDir;
- }
- else if( currentHist->path != currentDir )
- {
- // since we are adding a new path, delete everything after this path
- History *h = currentHist->next;
- while( h )
- {
- History *next = h->next;
- delete h;
- h = next;
- }
- currentHist->next = new History;
- currentHist->next->last = currentHist;
- currentHist = currentHist->next;
- currentHist->path = currentDir;
- }
- History * h = history;
- while( h )
- h = h->next;
- }
- walkingHistory = false;
- if( currentHist )
- {
- if( currentHist->last )
- backBtn->activate();
- else
- backBtn->deactivate();
- if( currentHist->next )
- forwardBtn->activate();
- else
- forwardBtn->deactivate();
- }
- }
- // treating the string as a '|' or ';' delimited sequence of patterns, strip them out and place in patterns
- // return whether it is likely that "s" represents a regexp file-matching pattern
- bool Flu_File_Chooser :: stripPatterns( FluSimpleString s, FluStringVector* patterns )
- {
- if( s.size() == 0 )
- return false;
- char *tok = strtok( (char*)s.c_str(), "|;" );
- int tokens = 0;
- while( tok )
- {
- tokens++;
- if( tok[0] == ' ' )
- tok++; // skip whitespace
- patterns->add( tok );
- tok = strtok( NULL, "|;" );
- }
- // if there is just a single token and it looks like it's not a pattern,
- // then it is probably JUST a filename, in which case it should not be
- // treated as a pattern
- if( _isProbablyAPattern( s.c_str() ) )
- return true;
- else if( tokens == 1 )
- {
- patterns->clear();
- return false;
- }
- else
- return true;
- }
- void Flu_File_Chooser :: cd( const char *path )
- {
- Entry *entry;
- char cwd[1024];
- if( !path || path[0] == '\0' )
- {
- path = getcwd( cwd, 1024 );
- if( !path )
- path = "./";
- }
- if( path[0] == '~' )
- {
- if( path[1] == '/' || path[1] == '\\' )
- sprintf( cwd, "%s%s", userHome.c_str(), path+2 );
- else
- sprintf( cwd, "%s%s", userHome.c_str(), path+1 );
- path = cwd;
- }
- lastSelected = 0;
- previewGroup->file = "";
- previewGroup->redraw();
- filelist->scroll_to_beginning();
- filescroll->position( 0, 0 );
- bool listMode = !fileDetailsBtn->value() || streq( path, FAVORITES_UNIQUE_STRING );
- #ifdef WIN32
- // refresh the drives if viewing "My Computer"
- if( strcmp( path, "/" ) == 0 )
- refreshDrives = true;
- #endif
- buildLocationCombo();
- filename.take_focus();
- trashBtn->deactivate();
- reloadBtn->activate();
- newDirBtn->activate();
- previewBtn->activate();
- hiddenFiles->activate();
- addFavoriteBtn->activate();
- resize( x(), y(), w(), h() );
- if( listMode )
- {
- //filecolumns->hide();
- //filescroll->hide();
- fileDetailsGroup->hide();
- filelist->show();
- filelist->parent()->resizable( filelist );
- }
- else
- {
- filelist->hide();
- //filecolumns->show();
- //filescroll->show();
- //filescroll->parent()->resizable( filescroll );
- fileDetailsGroup->show();
- fileDetailsGroup->parent()->resizable( fileDetailsGroup );
- //updateEntrySizes();
- }
- FluSimpleString currentFile = filename.value();
- filescroll->position( 0, 0 );
- //Fl::focus( &filename );
- upDirBtn->activate();
- ok.activate();
- // check for favorites
- if( streq( path, FAVORITES_UNIQUE_STRING ) )
- {
- currentDir = FAVORITES_UNIQUE_STRING;
- addToHistory();
- newDirBtn->deactivate();
- previewBtn->deactivate();
- reloadBtn->deactivate();
- addFavoriteBtn->deactivate();
- hiddenFiles->deactivate();
- location->input.value( favoritesTxt.c_str() );
- updateLocationQJ();
- filelist->clear();
- filedetails->clear();
- if( listMode )
- filelist->begin();
- else
- filedetails->begin();
- for( int i = 1; i <= favoritesList->size(); i++ )
- {
- entry = new Entry( favoritesList->text(i), ENTRY_FAVORITE, false/*fileDetailsBtn->value()*/, this );
- entry->updateSize();
- entry->updateIcon();
- }
- if( listMode )
- filelist->end();
- else
- filedetails->end();
- redraw();
- ok.deactivate();
- return;
- }
- // check for the current directory
- else if( streq( path, "." ) || streq( path, "./" ) || streq( path, ".\\" ) )
- {
- // do nothing. just rescan this directory
- }
- // check for parent directory
- else if( streq( path, ".." ) || streq( path, "../" ) || streq( path, "..\\" ) )
- {
- // if we are viewing the favorites and want to go back a directory, go to the previous directory
- if( currentDir == FAVORITES_UNIQUE_STRING )
- {
- backCB();
- return;
- }
- #ifdef WIN32
- // if we are at the desktop already, then we cannot go back any further
- //if( currentDir == "/Desktop/" )
- //{
- // do nothing
- //}
- //else if( currentDir == userHome+"Desktop/" )
- //currentDir = userHome;
- // if we are viewing "My Computer" and want to go back a directory, go to the desktop
- if( currentDir == "/" )
- {
- //currentDir = userDesktop;//userHome + "Desktop";
- // do nothing
- }
- // if we are at a top level drive, go to "My Computer" (i.e. "/")
- else if( currentDir[1] == ':' && currentDir[3] == '\0' )
- currentDir = "/";
- else
- #else
- // if the current directory is already as far back as we can go, ignore
- if( currentDir != "/" )
- #endif
- {
- // strip everything off the end to the next "/"
- int end = currentDir.size()-1;
- currentDir[end] = '\0';
- while( currentDir[end] != '/' )
- {
- currentDir[end] = '\0';
- end--;
- }
- }
- }
- // check for absolute path
- #ifdef WIN32
- else if( path[1] == ':' || path[0] == '/' )
- #else
- else if( path[0] == '/' )
- #endif
- {
- currentDir = path;
- }
- // else relative path
- else
- {
- // concatenate currentDir with path to make an absolute path
- currentDir += path;
- }
- int numDirs = 0, numFiles = 0;
- filelist->clear();
- filedetails->clear();
- cleanupPath( currentDir );
- #ifdef WIN32
- bool isTopDesktop = ( currentDir == ("/"+desktopTxt+"/") );
- bool isDesktop = correctPath( currentDir );
- if( isTopDesktop )
- upDirBtn->deactivate();
- #else
- if( currentDir == "/" )
- upDirBtn->deactivate();
- #endif
- #ifdef WIN32
- bool root = false;
- // check for my computer
- if( currentDir == "/" )
- {
- ok.deactivate();
- root = true;
- if( listMode )
- filelist->begin();
- else
- filedetails->begin();
- for( int i = 0; i < 26; i++ )
- {
- if( drives[i][0] != '\0' )
- {
- char drive[] = "A:/";
- drive[0] = 'A' + i;
- entry = new Entry( drive, ENTRY_DRIVE, fileDetailsBtn->value(), this );
- switch( driveTypes[i] )
- {
- case DRIVE_REMOVABLE: entry->description = diskTypesTxt[0].c_str(); break;
- case DRIVE_FIXED: entry->description = diskTypesTxt[2].c_str(); break;
- case DRIVE_CDROM: entry->description = diskTypesTxt[3].c_str(); break;
- case DRIVE_REMOTE: entry->description = diskTypesTxt[4].c_str(); break;
- case DRIVE_RAMDISK: entry->description = diskTypesTxt[5].c_str(); break;
- }
- entry->icon = driveIcons[i];
- entry->altname = drives[i];
- entry->updateSize();
- entry->updateIcon();
- }
- }
- if( listMode )
- filelist->end();
- else
- filedetails->end();
- redraw();
- }
- // check for desktop. if so, add My Computer and My Documents
- else if( isDesktop )
- {
- if( listMode )
- filelist->begin();
- else
- filedetails->begin();
- entry = new Entry( myDocumentsTxt.c_str(), ENTRY_MYDOCUMENTS, fileDetailsBtn->value(), this );
- entry->updateSize();
- entry->updateIcon();
- entry = new Entry( myComputerTxt.c_str(), ENTRY_MYCOMPUTER, fileDetailsBtn->value(), this );
- entry->updateSize();
- entry->updateIcon();
- if( listMode )
- filelist->end();
- else
- filedetails->end();
- numDirs += 2;
- }
- #endif
- // see if currentDir is in fact a directory
- // if so, make sure there is a trailing "/" and we're done
- if( fl_filename_isdir( currentDir.c_str() ) || currentDir=="/" )
- {
- if( currentDir[strlen(currentDir.c_str())-1] != '/' )
- currentDir += "/";
- #ifdef WIN32
- if( filename.value()[1] != ':' )
- #else
- if( filename.value()[0] != '/' )
- #endif
- {
- if( !(selectionType & SAVING ) )
- filename.value( "" );
- }
- if( !(selectionType & SAVING ) )
- currentFile = "";
- }
- // now we have the current directory and possibly a file at the end
- // try to split into path and file
- if( currentDir[currentDir.size()-1] != '/' )
- {
- char *lastSlash = (char *)strrchr( currentDir.c_str(), '/' );
- if( lastSlash )
- {
- currentFile = lastSlash+1;
- lastSlash[1] = '\0';
- }
- }
- // make sure currentDir ends in '/'
- if( currentDir[currentDir.size()-1] != '/' )
- currentDir += "/";
- #ifdef WIN32
- {
- FluSimpleString tmp = currentDir;
- if( isTopDesktop )
- currentDir = "/"+desktopTxt+"/";
- addToHistory();
- if( isTopDesktop )
- currentDir = tmp;
- }
- #else
- addToHistory();
- #endif
- delayedCd = "./";
- #ifdef WIN32
- // set the location input value
- // check for drives
- if( currentDir[1] == ':' && currentDir[3] == '\0' )
- {
- location->input.value( currentDir.c_str() );
- }
- else if( currentDir == "/" )
- location->input.value( myComputerTxt.c_str() );
- else
- #endif
- {
- location->input.value( currentDir.c_str() );
- #ifdef WIN32
- FluSimpleString treePath = "/"+desktopTxt+"/"+myComputerTxt+"/"+currentDir;
- Flu_Tree_Browser::Node *n = location->tree.add( treePath.c_str() );
- if( currentDir == (userHome+desktopTxt+"/") )
- n->branch_icon( &little_desktop );
- if( currentDir == (userHome+myDocumentsTxt+"/") )
- n->branch_icon( &documents );
- #else
- location->tree.add( currentDir.c_str() );
- #endif
- }
- updateLocationQJ();
- #ifdef WIN32
- if( root )
- return;
- #endif
- FluSimpleString pathbase, fullpath;
- bool isDir, isCurrentFile = false;
- const char *lastAddedFile = NULL, *lastAddedDir = NULL;
- pathbase = currentDir;
- // take the current pattern and make a list of filter pattern strings
- FluStringVector currentPatterns;
- {
- FluSimpleString pat = patterns[filePattern->list.value()-1];
- while( pat.size() )
- {
- int p = pat.find( ',' );
- if( p == -1 )
- {
- if( pat != "*" )
- pat = "*." + pat;
- currentPatterns.add( pat );
- break;
- }
- else
- {
- FluSimpleString s = pat.c_str() + p + 1;
- pat[p] = '\0';
- if( pat != "*" )
- pat = "*." + pat;
- currentPatterns.add( pat );
- pat = s;
- }
- }
- }
- // add any user-defined patterns
- FluStringVector userPatterns;
- // if the user just hit <Tab> but the filename input area is empty,
- // then use the current patterns
- if( !filenameTabCallback || currentFile != "*" )
- stripPatterns( currentFile, &userPatterns );
- // read the directory
- dirent **e;
- char *name;
- int num = fl_filename_list( pathbase.c_str(), &e );
- if( num > 0 )
- {
- int i;
- for( i = 0; i < num; i++ )
- {
- name = e[i]->d_name;
- // ignore the "." and ".." names
- if( strcmp( name, "." ) == 0 || strcmp( name, ".." ) == 0 ||
- strcmp( name, "./" ) == 0 || strcmp( name, "../" ) == 0 ||
- strcmp( name, ".\\" ) == 0 || strcmp( name, "..\\" ) == 0 )
- continue;
- // if 'name' ends in '/', remove it
- if( name[strlen(name)-1] == '/' )
- name[strlen(name)-1] = '\0';
- // file or directory?
- fullpath = pathbase + name;
- isDir = ( fl_filename_isdir( fullpath.c_str() ) != 0 );
- // was this file specified explicitly?
- isCurrentFile = ( currentFile == name );
- #ifndef WIN32
- // filter hidden files
- if( !isCurrentFile && !hiddenFiles->value() && ( name[0] == '.' ) )
- continue;
- #endif
- // only directories?
- if( (selectionType & DIRECTORY) &&
- !isDir &&
- !(selectionType & STDFILE) &&
- !(selectionType & DEACTIVATE_FILES) )
- continue;
- //if( !isDir /*!isCurrentFile*/ )
- {
- // filter according to the user pattern in the filename input
- if( userPatterns.size() )
- {
- bool cull = true;
- for( unsigned int i = 0; i < userPatterns.size(); i++ )
- {
- if( flu_filename_match( name, userPatterns[i].c_str() ) != 0 )
- {
- cull = false;
- break;
- }
- }
- if( cull )
- {
- // only filter directories if someone just hit <TAB>
- if( !isDir || ( isDir && filenameTabCallback ) )
- continue;
- }
- }
- // filter files according to the current pattern
- else
- {
- bool cull = true;
- for( unsigned int i = 0; i < currentPatterns.size(); i++ )
- {
- if( flu_filename_match( name, currentPatterns[i].c_str() ) != 0 )
- {
- cull = false;
- break;
- }
- }
- if( cull )
- {
- // only filter directories if someone just hit <TAB>
- if( !isDir || ( isDir && filenameTabCallback ) )
- continue;
- }
- }
- }
- // add directories at the beginning, and files at the end
- entry = new Entry( name, isDir?ENTRY_DIR:ENTRY_FILE, fileDetailsBtn->value(), this );
- if( isDir )
- {
- if( listMode )
- filelist->insert( *entry, 0 );
- else
- filedetails->insert( *entry, 0 );
- numDirs++;
- lastAddedDir = entry->filename.c_str();
- }
- else
- {
- if( listMode )
- filelist->add( entry );
- else
- filedetails->add( entry );
- numFiles++;
- lastAddedFile = entry->filename.c_str();
- }
- // get some information about the file
- struct stat s;
- ::stat( fullpath.c_str(), &s );
- // store size as human readable and sortable integer
- entry->isize = s.st_size;
- if( isDir && entry->isize == 0 )
- entry->filesize = "";
- else
- {
- char buf[32];
- /*
- if( (entry->isize >> 40) > 0 ) // terrabytes
- {
- double TB = double(entry->isize)/double(1<<40);
- sprintf( buf, "%.1f TB", TB );
- }
- */
- if( (entry->isize >> 30) > 0 ) // gigabytes
- {
- double GB = double(entry->isize)/double(1<<30);
- sprintf( buf, "%.1f GB", GB );
- }
- else if( (entry->isize >> 20) > 0 ) // megabytes
- {
- double MB = double(entry->isize)/double(1<<20);
- sprintf( buf, "%.1f MB", MB );
- }
- else if( (entry->isize >> 10) > 0 ) // kilabytes
- {
- double KB = double(entry->isize)/double(1<<10);
- sprintf( buf, "%.1f KB", KB );
- }
- else // bytes
- {
- sprintf( buf, "%d bytes", (int)entry->isize );
- }
- entry->filesize = buf;
- }
- // store date as human readable and sortable integer
- entry->date = formatDate( ctime( &s.st_mtime ) );//ctime( &s.st_mtime );
- entry->idate = s.st_mtime;
- // convert the permissions into UNIX style rwx-rwx-rwx (user-group-others)
- /*
- unsigned int p = s.st_mode;
- entry->pU = bool(p&S_IRUSR)<<2 | bool(p&S_IWUSR)<<1 | bool(p&S_IXUSR);
- entry->pG = bool(p&S_IRGRP)<<2 | bool(p&S_IWGRP)<<1 | bool(p&S_IXGRP);
- entry->pO = bool(p&S_IROTH)<<2 | bool(p&S_IWOTH)<<1 | bool(p&S_IXOTH);
- char* perms[8] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx" };
- entry->permissions = perms[entry->pU];
- entry->permissions += perms[entry->pG];
- entry->permissions += perms[entry->pO];
- */
- entry->updateSize();
- entry->updateIcon();
- if( isCurrentFile )
- {
- filename.value( name );
- entry->selected = true;
- lastSelected = entry;
- if( entry->type == ENTRY_FILE )
- previewGroup->file = currentDir + name;
- previewGroup->redraw();
- filelist->scroll_to( entry );
- filedetails->scroll_to( entry );
- //break;
- }
- }
- for( i = 0; i < num; i++ )
- free((void*)(e[i]));
- free((void*)e);
- }
- // sort the files: directories first, then files
- if( listMode )
- filelist->sort( numDirs );
- else
- filedetails->sort( numDirs );
- // see if the user pushed <Tab> in the filename input field
- if( filenameTabCallback )
- {
- filenameTabCallback = false;
- FluSimpleString prefix = commonStr();
- if( numDirs == 1 &&
- currentFile == (FluSimpleString(lastAddedDir)+"*") )
- {
- delay_cd( lastAddedDir );
- }
- if( numDirs == 1 && numFiles == 0 )
- {
- #ifdef WIN32
- if( filename.value()[1] == ':' )
- #else
- if( filename.value()[0] == '/' )
- #endif
- {
- FluSimpleString s = currentDir + lastAddedDir + "/";
- filename.value( s.c_str() );
- }
- else
- filename.value( lastAddedDir );
- }
- else if( numFiles == 1 && numDirs == 0 )
- {
- #ifdef WIN32
- if( filename.value()[1] == ':' )
- #else
- if( filename.value()[0] == '/' )
- #endif
- {
- FluSimpleString s = currentDir + lastAddedFile;
- filename.value( s.c_str() );
- }
- else
- filename.value( lastAddedFile );
- }
- else if( prefix.size() >= currentFile.size() )
- {
- #ifdef WIN32
- if( filename.value()[1] == ':' )
- #else
- if( filename.value()[0] == '/' )
- #endif
- {
- FluSimpleString s = currentDir + prefix;
- filename.value( s.c_str() );
- }
- else
- filename.value( prefix.c_str() );
- }
- if( currentFile == "*" &&
- #ifdef WIN32
- filename.value()[1] != ':' )
- #else
- filename.value()[0] != '/' )
- #endif
- {
- filename.value( "" );
- }
- }
- // see if the user pushed <Enter> in the filename input field
- if( filenameEnterCallback )
- {
- filenameEnterCallback = false;
- #ifdef WIN32
- if( filename.value()[1] == ':' )
- #else
- if( filename.value()[0] == '/' )
- #endif
- filename.value( "" );
- //if( isCurrentFile && numFiles == 1 )
- if( !_isProbablyAPattern( filename.value() ) )
- okCB();
- }
- if( _isProbablyAPattern( filename.value() ) )
- filename.position( 0, filename.size() );
- else
- filename.position( filename.size(), filename.size() );
- filename.take_focus();
- redraw();
- }
- // find the prefix string that is common to all entries in the list
- FluSimpleString Flu_File_Chooser :: commonStr()
- {
- FluSimpleString common;
- int index = 0;
- const char* name;
- int len, i;
- Fl_Group *g = getEntryGroup();
- for(;;)
- {
- bool allSkipped = true;
- for( i = 0; i < g->children(); i++ )
- {
- name = ((Entry*)g->child(i))->filename.c_str();
- len = strlen( name );
- if( index >= len )
- continue;
- allSkipped = false;
- if( i == 0 )
- common.push_back( name[index] );
- else if( toupper(common[index]) != toupper(name[index]) )
- {
- common[index] = '\0';
- return common;
- }
- }
- if( allSkipped )
- break;
- index++;
- }
- return common;
- }
- static const char* _flu_file_chooser( const char *message, const char *pattern, const char *filename, int type,
- int *count = 0, FluStringVector *filelist = 0 )
- {
- static Flu_File_Chooser *fc = NULL;
- static FluSimpleString retname;
- if( !fc )
- {
- fc = new Flu_File_Chooser( filename, pattern, type, message );
- }
- else
- {
- fc->type( type );
- fc->clear_history();
- fc->label( message );
- if( !filename || filename[0] == '\0' )
- {
- if( (!pattern || !fc->filter() || strcmp(pattern,fc->filter())) && fc->value() )
- {
- // if pattern is different, remove name but leave old directory:
- retname = fc->value();
- char *p = (char*)strrchr( retname.c_str(), '/' );
- if( p )
- {
- // If the filename is "/foo", then the directory will be "/", not ""
- if( p == retname.c_str() )
- retname[1] = '\0';
- else
- p[1] = '\0';
- }
- }
- fc->filter( pattern );
- fc->value( retname.c_str() );
- }
- else
- {
- fc->filter( pattern );
- fc->value( filename );
- }
- }
- fc->set_modal();
- fc->show();
- while( fc->shown() )
- Fl::wait( 0.01 );
- Fl_Group::current(0);
- if( fc->value() )
- {
- if( count && filelist )
- {
- *count = fc->count();
- for( int i = 1; i <= *count; i++ )
- filelist->add( FluSimpleString(fc->value(i)) );
- }
- retname = fc->value();
- return retname.c_str();
- }
- else
- return 0;
- }
- int flu_multi_file_chooser( const char *message, const char *pattern, const char *filename, FluStringVector *filelist )
- {
- int count = 0;
- _flu_file_chooser( message, pattern, filename, Flu_File_Chooser::MULTI, &count, filelist );
- return count;
- }
- const char* flu_file_chooser( const char *message, const char *pattern, const char *filename )
- {
- return _flu_file_chooser( message, pattern, filename, Flu_File_Chooser::SINGLE );
- }
- const char* flu_save_chooser( const char *message, const char *pattern, const char *filename )
- {
- return _flu_file_chooser( message, pattern, filename, Flu_File_Chooser::SINGLE | Flu_File_Chooser::SAVING );
- }
- const char* flu_dir_chooser( const char *message, const char *filename )
- {
- return _flu_file_chooser( message, "*", filename, Flu_File_Chooser::DIRECTORY );
- }
- const char* flu_dir_chooser( const char *message, const char *filename, bool showFiles )
- {
- if( showFiles )
- return _flu_file_chooser( message, "*", filename,
- Flu_File_Chooser::DIRECTORY | Flu_File_Chooser::DEACTIVATE_FILES );
- else
- return( flu_dir_chooser( message, filename ) );
- }
- const char* flu_file_and_dir_chooser( const char *message, const char *filename )
- {
- return _flu_file_chooser( message, "*", filename, Flu_File_Chooser::STDFILE );
- }
|