当前仓库属于暂停状态,部分功能使用受限,详情请查阅 仓库状态说明
26 Star 71 Fork 20

Surface-pro / Android日志分析工具
暂停

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
mainwindow.cpp 189.44 KB
一键复制 编辑 原始数据 按行查看 历史
Surface-pro 提交于 2017-08-14 17:08 . V3.5.3版本更新
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350
#include "mainwindow.h"
#include "ui_mainwindow.h"
#define ON 1 //开
#define OFF 0 //关
//#define DEBUG_SWITCH ON //打印信息输出开关
#define DEBUG_SWITCH OFF //打印信息输出开关
#define DEFAULT_TAG "All messages" //默认的日志Tag,即显示所有信息
#define ADB_ERR_RESULT "'adb' " //ADB返回的错误信息
#define MAX_CACHE_LINES 500000 //日志文件最大缓存数据行数
#define MAX_TERNIMAL_CACHE_LINES 500000 //实时终端模式下日志最大缓存数据行数
#define LOG_CACHE_FILE_PATH "/cache/logCache.log" //日志缓存文件路径
#define LOG_REBUILD_FILE_PATH "/cache/rebuild.log" //重构日志缓存文件的路径
#define SETTING_FILE_PATH "/config/setting.cfg" //软件的全局配置文件
#define TEMP_SETTING_FILE_PATH "/config/temp.cfg" //软件的全局配置文件的临时文件
#define BACKUP_SETTING_FILE_PATH "/config/backup_setting.cfg" //软件的全局配置文件的备份文件
#define WORK_MODE_OFFLINE " 离线查看模式 " //工作模式--离线查看模式
#define WORK_MODE_ONLINE " 实时终端模式 " //工作模式--实时终端模式
#define NO_ADB_DEVICE " ADB设备未连接 " //无ADB设备
#define MAX_SAVE_HISTORY_NUM 10 //最大文件打开历史记录数量
#define DEFAULT_HISTORY_ACTION "清空历史记录" //清空文件打开历史记录Action动作名称
#define LED_ID_ADB_STATUS 1 //ADB连接状态指示灯
#define MAX_CACHE_FILE_SIZE (MAX_CACHE_LINES * 102) //根据最大缓存行数预估的最大文件大小(大致每10行为1K)
#define ALREADY_CMD_EXEC "Already cmd exec" //已经有命令在执行
/*
* 函数名称: MainWindow(QWidget *parent)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.1.20
* 函数功能: 构造函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//软件UI属性配置
ui->setupUi(this); //装在UI文件
setWindowTitle("Android日志分析工具 V3.5.3"); //设置软件标题
setWindowState(Qt::WindowMaximized); //设置软件启动时为最大化窗口
//初始化软件运行环境
initEnvironment();
//设置信号与槽的连接
QObject::connect(ui->menuBar,SIGNAL(triggered(QAction*)),this,SLOT(trigerMenuSlot(QAction*)));
QObject::connect(ui->cbLevel,SIGNAL(currentIndexChanged(int)),this,SLOT(logLevelChangedSlot()));
QObject::connect(ui->etSearch,SIGNAL(returnPressed()),this,SLOT(searchEditChangedSlot()));
QObject::connect(ui->swTimeFilter,SIGNAL(clicked()),this,SLOT(swTimeFilterChangedSlot()));
QObject::connect(ui->swTime,SIGNAL(clicked()),this,SLOT(swMessageFilterChangedSlot()));
QObject::connect(ui->swLevel,SIGNAL(clicked()),this,SLOT(swMessageFilterChangedSlot()));
QObject::connect(ui->swPID,SIGNAL(clicked()),this,SLOT(swMessageFilterChangedSlot()));
QObject::connect(ui->swTag,SIGNAL(clicked()),this,SLOT(swMessageFilterChangedSlot()));
QObject::connect(ui->swHead,SIGNAL(clicked()),this,SLOT(swMessageFilterChangedSlot()));
QObject::connect(ui->history,SIGNAL(triggered(QAction*)),this,SLOT(trigerHistorySlot(QAction*)));
QObject::connect(ui->cbPID,SIGNAL(currentIndexChanged(int)),this,SLOT(cbPIDChangedSlot()));
QObject::connect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
QObject::connect(ui->lwContent,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(curContentChangedSlot()));
isConnectTimeFilter(true); //建立时间过滤器的信号与槽的连接
isConnectScroll(true); //建立内容显示区的垂直滚动条的信号与槽的连接
startTimer->start(500);
}
/*
* 函数名称: ~MainWindow()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.1.20
* 函数功能: 析构函数,用于释放软件所占用的资源
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
MainWindow::~MainWindow()
{
delete ui;
}
/*
* 函数名称: loadSoftwareSetting()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.16
* 函数功能: 加载软件的设置文件
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::loadSoftwareSetting(QString path)
{
//创建配置文件解析器
mSettingParse = new ParseSettingFile(this,path);
//从解析器中获取解析后的参数
mCurFontType = mSettingParse->getFontType();
mCurFontSize = mSettingParse->getFontSize();
mCurCodeType = mSettingParse->getCodeType();
ADBPath = mSettingParse->getADBPath();
mRegisterNum = mSettingParse->getRegisterNum();
mHistory = mSettingParse->getHistory();
isApplyOfflineMode = mSettingParse->getIsApplyOfflineMode();
isApplyRealtimeMode = mSettingParse->getIsApplyRealtimeMode();
isFirstFilter = mSettingParse->getIsFirstFilter();
isSecondFilter = mSettingParse->getIsSecondFilter();
mFirstSysFilters = mSettingParse->getFirstSysFilters();
mSecondSysFilters = mSettingParse->getSecondSysFilters();
isApplyDebugApp = mSettingParse->getIsApplyDebugApp();
mCurDebugApp = mSettingParse->getCurDebugApp();
Security *security = Security::getInstance();
if (security->checkRegisterNum(mRegisterNum)) {
security->setRegisted(true);
} else {
security->setRegisted(false);
}
updateHistoryAction(mHistory);
}
/*
* 函数名称: initEnvironment()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.14
* 函数功能: 初始化相关变量
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::initEnvironment()
{
//此处变量定义必须放在最前面
mEventLoop = new QEventLoop;
eventLoopTimer = new QTimer(this);
QObject::connect(eventLoopTimer,SIGNAL(timeout()),this,SLOT(eventLoopTimeoutSlot()));
mWindowsUserPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/LogCatTool";
QDir dir(mWindowsUserPath);
if (!dir.exists()) {
dir.mkdir(mWindowsUserPath);
}
logCurTime("我的文档路径:" + mWindowsUserPath);
mLogCacheFilePath = QCoreApplication::applicationDirPath() + LOG_CACHE_FILE_PATH;
logCurTime("当前日志缓存路径:" + mLogCacheFilePath);
//读取日志缓存目录,构建备份文件数据表mBackupCacheFilePath
QString tempPath = QCoreApplication::applicationDirPath() + "/cache";
QDir tempDir(tempPath);
QFileInfoList infoList = tempDir.entryInfoList(QDir::Files);
for (int i = 0; i < infoList.size(); ++i) {
QString name = infoList.at(i).baseName();
if (name.contains("-") && (name.split("-").at(0) == "logCache")) {
mBackupCacheFilePath.append(infoList.at(i).absoluteFilePath());
} else if (name.contains("rebuild")) {
mBackupCacheFilePath.append(infoList.at(i).absoluteFilePath());
}
}
mSettingFilePath = mWindowsUserPath + SETTING_FILE_PATH;
logCurTime("当前全局设置文件路径:" + mSettingFilePath);
//加载软件的设置文件,并设置相应的参数
loadSoftwareSetting(mSettingFilePath);
//初始化文件打开历史记录
if (ui->history->actions().size() > 2) {
ui->history->setEnabled(true);
} else {
ui->history->setEnabled(false);
}
//创建软件底部状态栏的标签
fileLabel = new QLabel;
adbStatusLabel = new QLabel;
adbDeviceLabel = new QLabel;
workModeLabel = new QLabel;
curDebugAppLabel = new QLabel;
adbStatusLabel->setFixedSize(15,15);
//样式表的设置
ui->statusBar->setStyleSheet("QStatusBar::item{border:0px;}"
"QStatusBar{background-color:rgb(54,54,54);}");
fileLabel->setStyleSheet("background-color:rgb(30,30,30);color:rgb(200,200,200);");
adbDeviceLabel->setStyleSheet("background-color:rgb(30,30,30);color:rgb(200,200,200);");
workModeLabel->setStyleSheet("background-color:rgb(30,30,30);color:rgb(200,200,200);");
curDebugAppLabel->setStyleSheet("background-color:rgb(30,30,30);color:rgb(200,200,200);");
adbDeviceLabel->setMaximumWidth(600);
fileLabel->setMaximumWidth(600);
curDebugAppLabel->setMaximumWidth(400);
ui->statusBar->addWidget(workModeLabel);
ui->statusBar->addWidget(adbStatusLabel);
ui->statusBar->addWidget(adbDeviceLabel);
ui->statusBar->addWidget(fileLabel);
ui->statusBar->addWidget(curDebugAppLabel);
//软件启动时默认为“离线查看模式”
adbDeviceLabel->setText(NO_ADB_DEVICE);
ledOff(LED_ID_ADB_STATUS);
workModeLabel->setText(WORK_MODE_OFFLINE);
//时间信息过滤器默认失能
ui->swTimeFilter->setChecked(false);
//获取UI控件对象
lwFilter = ui->lwFilter;
lwContent = ui->lwContent;
labelLine = ui->labelLine;
labelTime = ui->labelTime;
labelLevel = ui->labelLevel;
labelPID = ui->labelPID;
labelTag = ui->labelTag;
labelText = ui->labelText;
//相关变量初始化
isDispTime = true;
isDispLevel = true;
isDispPID = true;
isDispTag = true;
isDispHead = true;
logFileSize = 0;
mCurLogFilePath = "";
mLastSearchText = "";
mCurDebugAppPID = "";
cmdProcess = NULL;
mCurADBDeviceStatus = false;
isTerminalMode = false;
mLastScrollValue = 0;
isCheckedUpdateFile = false;
mReConnecCnt = 0;
isLoadingFile = false;
isScaningADBDevice = false;
mFilterChangedFlag = false;
isLedOn = false;
isSearching = false;
isExitSearch = false;
isPageOffsetMode = false;
isNeedBackupCacheFile = false;
isPeopleExitTerminal = false;
isStartADBServer = false;
isExitEventLoop = false;
isCheckingPID = false;
isClickRestart = false;
mGotoLine = "";
mAllLines = 0;
mCurLines = 0;
mLastPos = 0;
mCurPageIndex = 0;
mPageNum = 0;
mLogType = LOG_TYPE_UNKNOWN;
clearAllPageOffset();
mCurOptDialog = NULL;
mWaitDialog = new QWaitDialog(this,"");
mTagAnalyseDialog = new TagAnalyse;
mCurRange = new ItemsRange(this,0,0,0,0,0);
ui->verticalScrollBar->setHidden(true);
ui->labelPage->setHidden(true);
ui->cbPage->setHidden(true);
startTimer = new QTimer(this);
QObject::connect(startTimer,SIGNAL(timeout()),this,SLOT(startTimeoutSlot()));
fileTimer = new QTimer(this);
QObject::connect(fileTimer,SIGNAL(timeout()),this,SLOT(fileTimeoutSlot()));
statusTimer = new QTimer(this);
QObject::connect(statusTimer,SIGNAL(timeout()),this,SLOT(statusTimeoutSlot()));
clearAllDataList(); //初始化全局数据表
//设置文本字体样式
QFont font = QFont(mCurFontType,mCurFontSize,QFont::Normal);
lwFilter->setFont(font);
lwFilter->setStyleSheet("QListWidget{color:#FFC5C5C5;}"
"QListWidget::Item:selected{background:#80ABABAB;}"
"QListWidget::Item:hover{background:#40ABABAB;}");
lwContent->setFont(font);
lwContent->setStyleSheet("QListWidget::Item:selected{background:#80ABABAB;}"
"QListWidget::Item:hover{background:#40ABABAB;}");
labelLine->setFont(font);
labelTime->setFont(font);
labelLevel->setFont(font);
labelPID->setFont(font);
labelTag->setFont(font);
labelText->setFont(font);
//默认离线模式下禁止清空当前显示按钮
ui->actionClearCurDisp->setEnabled(false);
//创建日志等级颜色配色表
QString colorStr = "#0843CE,#007BB9,#007F00,#FF7F00,#FF0000,#A50000,#FFFFFF";
QStringList corlorList = colorStr.split(",");
mColorConfig = new QList<QColor>;
for (int i = 0; i < 7; ++i) {
mColorConfig->append(QColor(corlorList.at(i)));
}
}
/*******************************************************************************************
* 普通槽函数区域
* *****************************************************************************************/
/*
* 函数名称: trigerMenuSlot(QAction* action)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 软件菜单栏触发槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::trigerMenuSlot(QAction* action)
{
/***************** 文件菜单 *********************/
//打开文件
if (action == ui->actionOpen) {
openFileAction();
}
//重载文件动作
else if (action == ui->actionRefresh) {
refreshLogFileAction();
}
//关闭文件
else if (action == ui->actionClose) {
closeFileAction();
}
//重启软件
else if (action == ui->actionRestart) {
restartSoftwareAction();
}
//退出软件
else if (action == ui->actionExit) {
close();
}
/***************** 搜索菜单 *********************/
//跳转到行
else if (action == ui->actionGotoLine) {
gotoLineAction();
}
//跳转到上一页
else if (action == ui->actionLastPage) {
lastPageAction();
}
//跳转到下一页
else if (action == ui->actionNextPage) {
nextPageAction();
}
//页分界切换
else if (action == ui->actionPageOffset) {
pageOffsetAction();
}
/***************** 工具菜单 *********************/
//ADB连接动作
else if (action == ui->actionConnectADB) {
connectADBAction();
}
//工作模式切换动作
else if (action == ui->actionTerminal) {
clickTerminalAction();
}
//Tag分析
else if (action == ui->actionTagAnalyse) {
openTagAnalyseWindowsAction();
}
//清空当前显示
else if (action == ui->actionClearCurDisp) {
clearCurDispAction();
}
//安装APK到设备
else if (action == ui->actionInstallAPK) {
installAPKAction();
}
/***************** 设置菜单 *********************/
//选项配置
else if (action == ui->actionSetting) {
setingAction();
}
//备份配置文件
else if (action == ui->actionBackup) {
backupSettingFileAction();
}
//导入配置文件
else if (action == ui->actionImport) {
importSettingFileAction();
}
/***************** 帮助菜单 *********************/
//关于软件
else if (action == ui->actionAbout) {
aboutAction();
}
//软件注册
else if (action == ui->actionRegister) {
registerSolftwareAction();
}
}
/*
* 函数名称: trigerHistorySlot(QAction *action)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.16
* 函数功能: 文件打开历史记录触发槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::trigerHistorySlot(QAction *action)
{
//如果是清空历史记录
if (action->text() == DEFAULT_HISTORY_ACTION) {
QList<QAction*> list = ui->history->actions();
QMenu *history = ui->history;
int size = list.size();
for (int i = 0; i < (size - 1); ++i) {
history->removeAction(list.at(i));
}
history->setEnabled(false);
}
//否则为打开选中的文件
else {
QString path = action->text();
//如果选中的文件还未打开
if (path != mCurLogFilePath) {
resetPageParams();
loadFile(path);
} else {
QMessageBox::information(this,"警告","该文件已经打开!");
}
}
}
/*
* 函数名称: logLevelChangedSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 日志等级发生了改变
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::logLevelChangedSlot()
{
filterChangedSlot();
}
/*
* 函数名称: filterChangedSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 当前选中的过滤器发生了变化
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::filterChangedSlot()
{
mFilterChangedFlag = true;
dispContainSearchString(ui->etSearch->text());
//如果当前是实时终端模式,切换后显示内容的最后一行,以便达到显示最新内容的目的
if (isTerminalMode) {
ui->verticalScrollBar->setValue(ui->verticalScrollBar->maximum());
if (lwContent->count() > 0) {
lwContent->setCurrentRow(lwContent->count() - 1);
}
}
}
/*
* 函数名称: searchEditChangedSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 日志搜索栏发生了改变
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::searchEditChangedSlot()
{
//如果搜索内容未发生变化,则无需重复搜索
if (mLastSearchText == ui->etSearch->text()) {
return;
}
logCurTime("开始搜索...");
//创建并显示加载进度条
isSearching = true;
mSearchDialog = new QProgressDialog;
QObject::connect(mSearchDialog,SIGNAL(canceled()),this,SLOT(exitSearchSlot()));
mSearchDialog->setCancelButton(0);
mSearchDialog->setLabelText("正在搜索,请稍后....");
mSearchDialog->setMinimum(0);
mSearchDialog->setMaximum(100);
mSearchDialog->setValue(0);
mSearchDialog->setModal(true);
mSearchDialog->show();
mainThreadWait_ms(10); //阻塞主线程10ms,只有阻塞主线程,进度条才有机会显示出来
//创建数据备份区
QStringList backupCurTimes = mCurTimes;
QStringList backupCurLevels = mCurLevels;
QStringList backupCurPIDs = mCurPIDs;
QStringList backupCurTags = mCurTags;
QStringList backupCurTexts = mCurTexts;
//开始搜索
dispContainSearchString(ui->etSearch->text());
//如果用户在搜索过程中人为的停止了搜索,则恢复搜索前的数据
if (isExitSearch) {
mCurTimes = backupCurTimes;
mCurLevels = backupCurLevels;
mCurPIDs = backupCurPIDs;
mCurTags = backupCurTags;
mCurTexts = backupCurTexts;
mCurLines = mCurTags.size();
updateCurRange(); //更新当前显示缓冲区范围
//自动更新时间过滤器的起止时间显示
if (mCurTimes.isEmpty()) {
mStartTime = "01-01 00:00:00.000";
mStopTime = "01-01 00:00:00.000";
} else {
mStartTime = mCurTimes.at(0);
mStopTime = mCurTimes.at(mCurLines - 1);
}
updateTimeStringToWidget(mStartTime,mStopTime);
//显示当前数据表
dispCurDataList();
logCurTime("退出搜索");
} else {
mSearchDialog->close();
mainThreadWait_ms(10);
logCurTime("搜索完毕");
}
//清空数据备份区
backupCurTimes.clear();
backupCurLevels.clear();
backupCurPIDs.clear();
backupCurTags.clear();
backupCurTexts.clear();
QObject::disconnect(mSearchDialog,SIGNAL(canceled()),this,SLOT(exitSearchSlot()));
delete mSearchDialog;
isExitSearch = false;
isSearching = false;
mLastSearchText = ui->etSearch->text();
}
/*
* 函数名称: swTimeFilterChangedSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 时间过滤开关变化槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::swTimeFilterChangedSlot()
{
//如果使能了时间过滤器
if (ui->swTimeFilter->isChecked()) {
//从控件中读取时间信息并进行格式化重构
mStartTime = ui->cbStartMonth->currentText() + "-" + ui->cbStartDay->currentText()
+ " " + ui->cbStartHour->currentText() + ":" + ui->cbStartMinute->currentText()
+ ":" + ui->cbStartSecond->currentText() + ".000";
mStopTime = ui->cbStopMonth->currentText() + "-" + ui->cbStopDay->currentText()
+ " " + ui->cbStopHour->currentText() + ":" + ui->cbStopMinute->currentText()
+ ":" + ui->cbStopSecond->currentText() + ".000";
//如果起始时间大于终止时间
if (QString::compare(mStartTime,mStopTime) > 0) {
ui->swTimeFilter->setChecked(false);
QMessageBox::information(this,"警告","时间设置错误,应满足【起始时间 <= 终止时间】!");
return;
}
}
//如果失能了时间过滤器
else {
//若当前数据表为空则初始化为固定值,否则设置为整个时间区域
if (mCurTimes.isEmpty()) {
mStartTime = "01-01 00:00:00.000";
mStopTime = "01-01 00:00:00.000";
} else {
mStartTime = mCurTimes.at(0);
mStopTime = mCurTimes.at(mCurLines - 1);
}
//更新时间信息到控件显示
updateTimeStringToWidget(mStartTime,mStopTime);
}
//刷新显示
if (!mCurTimes.isEmpty()) {
dispContainSearchString(ui->etSearch->text());
}
}
/*
* 函数名称: timeFilterChangedSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 时间过滤选择框变化槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::timeFilterChangedSlot()
{
if (ui->swTimeFilter->isChecked()) {
//从控件中读取时间信息并进行格式化重构
mStartTime = ui->cbStartMonth->currentText() + "-" + ui->cbStartDay->currentText()
+ " " + ui->cbStartHour->currentText() + ":" + ui->cbStartMinute->currentText()
+ ":" + ui->cbStartSecond->currentText() + ".000";
mStopTime = ui->cbStopMonth->currentText() + "-" + ui->cbStopDay->currentText()
+ " " + ui->cbStopHour->currentText() + ":" + ui->cbStopMinute->currentText()
+ ":" + ui->cbStopSecond->currentText() + ".000";
//如果起始时间大于终止时间
if (QString::compare(mStartTime,mStopTime) > 0) {
ui->swTimeFilter->setChecked(false);
QMessageBox::information(this,"警告","时间设置错误,应满足【起始时间 <= 终止时间】!");
return;
}
//刷新显示
if (!mCurTimes.isEmpty()) {
dispContainSearchString(ui->etSearch->text());
}
}
}
/*
* 函数名称: swMessageFilterChangedSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 信息过滤开关变化槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::swMessageFilterChangedSlot()
{
isDispTime = !ui->swTime->isChecked();
isDispLevel = !ui->swLevel->isChecked();
isDispPID = !ui->swPID->isChecked();
isDispTag = !ui->swTag->isChecked();
isDispHead = !ui->swHead->isChecked();
//根据信息过滤器的开关状态设置是否显示对应的标签
ui->labelTime->setVisible(isDispTime);
ui->labelLevel->setVisible(isDispLevel);
ui->labelPID->setVisible(isDispPID);
ui->labelTag->setVisible(isDispTag);
//刷新显示
dispContainSearchString(ui->etSearch->text());
}
/*
* 函数名称: threadDoneSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.14
* 函数功能: 执行ADB命令线程完毕槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::threadDoneSlot()
{
//logCurTime("线程执行完毕");
//mEventLoop->exit();
isExitEventLoop = true;
}
/*
* 函数名称: showDialogSlot()
* 函数版本: 1.0.0
* 函数版本: 1.0.1 【修复同时多次显示对话框而无法正常关闭,导致软件死机的BUG】
* 作者: HXL
* 创建日期: 2017.3.14
* 函数功能: 显示等待对话框槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::showDialogSlot()
{
//logCurTime("显示等待对话框");
//避免重复显示,造成显示多个对话框无法关闭,引起软件死机的BUG
if (mCurADBDeviceStatus || mWaitDialog->isVisible()) {
//logCurTime("显示失败");
return;
}
QString title;
if (mCurADBDeviceStatus) {
title = "正在重连ADB服务器....";
} else {
title = "正在启动ADB服务器....";
}
mReConnecCnt++;
delete mWaitDialog;
mWaitDialog = new QWaitDialog(this,title);
mWaitDialog->exec();
}
/*
* 函数名称: closeDialogSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.14
* 函数功能: 关闭等待对话框槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::closeDialogSlot()
{
//logCurTime("关闭等待对话框");
mWaitDialog->close();
}
/*
* 函数名称: gotoLineEditTextChangedSLot(QString text)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.16
* 函数功能: 跳转到行输入编辑框当前文本发生变化触发槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::gotoLineEditTextChangedSLot(QString text)
{
mGotoLine = text;
}
/*
* 函数名称: gotoLineSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.16
* 函数功能: 跳转到指定行槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::gotoLineSlot()
{
QString text = mGotoLine;
if (text.isEmpty()) {
mCurOptDialog->close();
return;
}
int length = text.length();
QChar temp;
for (int i = 0; i < length; ++i) {
temp = text.at(i);
if ((temp < '0') || (temp > '9')) {
QMessageBox::information(this,"警告","行号无效,必须为纯数字!");
return;
}
}
int line = text.toInt();
if ((line <= 0) || (line > mCurLines)) {
QMessageBox::information(this,"警告","行号无效,不在指定的范围内!");
return;
}
mCurOptDialog->close();
//更新当前显示缓冲区范围
int visibleFirst = line - mCurRange->getPageItemNum() / 2;
int first = visibleFirst - 1;
delete mCurRange;
mCurRange = new ItemsRange(this,first,visibleFirst,mCurRange->getCount(),
mCurRange->getPageItemNum(),mCurLines);
dispAreaData(mCurRange,0); //显示缓冲区的数据
//将焦点定位到跳转的行
int count = mCurRange->getCount();
int bitNum = QString::number(mCurLines).length();
QListWidgetItem *item;
for (int i = 0; i < count; ++i) {
item = lwContent->item(i);
if (item == NULL) {
continue;
} else if (line == item->text().mid(0,bitNum).toInt()) {
isConnectScroll(false);
lwContent->setCurrentRow(i);
isConnectScroll(true);
break;
}
}
}
/*
* 函数名称: cbPIDChangedSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.20
* 函数功能: 进程筛选框变化槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::cbPIDChangedSlot()
{
QObject::disconnect(ui->lwFilter,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(filterChangedSlot()));
updateCurFilters();
//最后默认选中第一行,并显示所有日志内容
if (lwFilter->count() > 0) {
lwFilter->setCurrentRow(0);
}
updateCurRange();
QObject::connect(ui->lwFilter,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(filterChangedSlot()));
filterChangedSlot();
}
/*
* 函数名称: exitSearchSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.28
* 函数功能: 退出搜索槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::exitSearchSlot()
{
isExitSearch = true;
}
/*
* 函数名称: gotoPageSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.3
* 函数功能: 跳转到指定页
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::gotoPageSlot()
{
QString text = ui->cbPage->currentText();
int length = text.length();
text = text.mid(1,length - 2);
if (!stringIsNum(text)) {
QMessageBox::information(this,"警告","获取页索引失败!");
return;
}
mCurPageIndex = text.toInt() - 1;
if (mCurPageIndex < 0) {
mCurPageIndex = 0;
} else if (mCurPageIndex >= MAX_PAGE_NUM) {
mCurPageIndex = MAX_PAGE_NUM - 1;
}
loadFile(mCurLogFilePath);
}
/*
* 函数名称: curContentChangedSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.25
* 函数功能: 日志内容区域当前选中项发生了改变
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::curContentChangedSlot()
{
logCurTime("当前项改变了");
if (lwContent->count() > 0) {
int count = lwContent->count();
QListWidgetItem *item = lwContent->currentItem();
if (item == NULL) {
return;
}
QString text = item->text();
while(text.contains(" ")) {
text.replace(" "," ");
}
QString level = text.split(" ").at(3);
QColor color = mColorConfig->at(getLevelIndex(level));
//将对应日志等级的文本设置成对应的颜色
lwContent->setStyleSheet("QListWidget::Item:selected{background:#40ABABAB; color:" + color.name() + "}"
"QListWidget::Item:hover{background:#20ABABAB;}");
}
logCurTime("结束");
}
/*
* 函数名称: selfVerticalScrollSlot(int value)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.10
* 函数功能: QListWidget自带的垂直滚动条值变化槽函数
* 实现机制:通过控制自带的滚动条,来达到自定义滚动条控制显示内容的目的,
* 具体逻辑的实现较复杂,此处不做详细介绍;
* 输入参数: value:滚动条当前的值
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::selfVerticalScrollSlot(int value)
{
logCurTime("内部滑动:value=" + QString::number(value) + ", mLastScrollValue=" + QString::number(mLastScrollValue));
int direction = 0;
int step = value - mLastScrollValue;
//与上一次的值作比较,判断滑动的方向,1表示向下滑动,-1表示向上滑动,0表示未滑动
if (value > mLastScrollValue) {
direction = 1;
} else if (value < mLastScrollValue) {
direction = -1;
}
//logCurTime("由" + QString::number(mLastScrollValue) + " >> " + QString::number(value));
//如果是向下滑动
if (direction == 1) {
int first = mCurRange->getFirst();
int visibleFirst = mCurRange->getVisibleFirst();
int count = mCurRange->getCount();
int pageItemNum = mCurRange->getPageItemNum();
if ((visibleFirst != 0)
&& (mCurRange->getLast() != (mCurLines - 1))) {
first += step;
} else {
mLastScrollValue = value;
}
visibleFirst += step;
delete mCurRange;
mCurRange = new ItemsRange(this,first,visibleFirst,count,pageItemNum,mCurLines);
dispAreaData(mCurRange,direction);
}
//如果是向上滑动
else if (direction == -1) {
int first = mCurRange->getFirst();
int visibleFirst = mCurRange->getVisibleFirst();
int count = mCurRange->getCount();
int pageItemNum = mCurRange->getPageItemNum();
if ((first != 0)
&& (mCurRange->getLast() != (mCurLines - 1))) {
first += step;
} else if (mCurRange->getLast() == (mCurLines - 1)) {
if ((visibleFirst + step) <= first) {
first += step;
if ((value == 0) && (first != 0)) {
mLastScrollValue = visibleFirst + step - first;
}
} else {
mLastScrollValue = value;
}
} else {
mLastScrollValue = value;
}
visibleFirst += step;
delete mCurRange;
mCurRange = new ItemsRange(this,first,visibleFirst,count,pageItemNum,mCurLines);
dispAreaData(mCurRange,direction);
}
//如果未滑动
else if (value == 0) {
mLastScrollValue = 3;
lwContent->verticalScrollBar()->setValue(1);
}
}
/*
* 函数名称: verticalScrollSlot(int value)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.10
* 函数功能: 自定义的垂直滚动条值变化槽函数
* 输入参数: value:滚动条当前的值
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::verticalScrollSlot(int value)
{
logCurTime("外部滑动:value=" + QString::number(value));
int visibleFirst = value;
int first = (visibleFirst > 0) ? (visibleFirst - 1) : visibleFirst;
int count = mCurRange->getCount();
int pageItemNum = mCurRange->getPageItemNum();
delete mCurRange;
mCurRange = new ItemsRange(this,first,visibleFirst,count,pageItemNum,mCurLines);
dispAreaData(mCurRange,0);
}
/*******************************************************************************************
* 定时器槽函数区域
* *****************************************************************************************/
/*
* 函数名称: startTimeoutSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.4
* 函数功能: 软件启动界面显示完后触发的槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::startTimeoutSlot()
{
startTimer->stop();
//清空日志缓存文件(如果存在的话),防止上一次软件异常闪退导致缓存文件未删除的BUG
clearLogCacheFile();
}
/*
* 函数名称: fileTimeoutSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: 日志缓存文件大小监控定时器槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::fileTimeoutSlot()
{
fileTimer->stop();
static bool hasFirstBreak = false;//是否第一次跳转过了
static int cnt = 0;
int size = logFileSize;
QFile *file = new QFile(mLogCacheFilePath);
if (file->exists()) {
size = file->size();
}
file->close();
delete file;
cnt++;
if (cnt >= 100) {
cnt = 0;
}
//每210ms监测一次设备运行的进程
if ((cnt % 21) == 0) {
//是否启用了调试指定APP的功能,且ADB设备处于连接状态,且无事件在运行
//if (isApplyDebugApp && mCurADBDeviceStatus && !mEventLoop->isRunning()) {
if (isApplyDebugApp && mCurADBDeviceStatus && statusTimer->isActive()) {
isCheckingPID = true;
//查找该包名对应的进程号是否存在
QStringList result = execWindowsCmd(ADBPath,"adb -s " + mCurADBDevice
+ " shell ps");
QStringList threadList = result.at(0).split("\n");
int num = threadList.size();
QString temp1;
QStringList temp2;
QString oldAppPID;
bool isFind = false;
//逆序查找速度更快
for (int i = 0; i < num; ++i) {
temp1 = threadList.at(num - i - 1);
if (temp1.contains(mCurDebugApp)) {
while(temp1.contains(" ")) {
temp1.replace(" "," ");
}
temp2 = temp1.split(" ");
//共有9个信息栏
if (temp2.size() >= 9) {
oldAppPID = mCurDebugAppPID;
mCurDebugAppPID = temp2.at(1);
//logCurTime("进程号:" + mCurDebugAppPID);
//如果进程号发生了改变
if (oldAppPID != mCurDebugAppPID) {
hasFirstBreak = false;
if (mCurDebugAppPID != "") {
// curDebugAppLabel->setText("当前调试APP:" + mCurDebugApp
// + "(" + mCurDebugAppPID + ")");
QFontMetrics elidFont(curDebugAppLabel->font());
curDebugAppLabel->setText(elidFont.elidedText("当前调试APP:" + mCurDebugApp
+ "(" + mCurDebugAppPID + ")",
Qt::ElideMiddle,curDebugAppLabel->maximumWidth()));
} else {
curDebugAppLabel->setText("");
}
}
//是否第一次跳转过
if (!hasFirstBreak) {
int index = ui->cbPID->findText(mCurDebugAppPID);
if (index != -1) {
ui->cbPID->setCurrentIndex(index);
hasFirstBreak = true;
}
}
//如果找到了则立即跳出循环,节省时间
isFind = true;
break;
}
}
}
if (!isFind) {
mCurDebugAppPID = "";
curDebugAppLabel->setText("");
}
isCheckingPID = false;
} else if (!isApplyDebugApp) {
mCurDebugAppPID = "";
curDebugAppLabel->setText("");
}
}
//如果文件大小发生了变化,则重新加载该文件,以显示最新的文件内容,达到实时显示的目的
if (logFileSize != size) {
//logCurTime("logFileSize=" + QString::number(logFileSize) + ", size=" + QString::number(size));
logFileSize = size;
//记录更新文件内容前的相关显示参数
int oldFilterRow = lwFilter->currentRow();
int oldContentRow = lwContent->currentRow();
int oldFilterScrollPosition = lwFilter->verticalScrollBar()->value();
bool isMax = (ui->verticalScrollBar->value() == ui->verticalScrollBar->maximum()) ? true : false;
oldFilterRow = (oldFilterRow > 0) ? oldFilterRow : 0;
oldContentRow = (oldContentRow > 0) ? oldContentRow : 0;
oldFilterScrollPosition = (oldFilterScrollPosition > 0) ? oldFilterScrollPosition : 0;
QString oldFilterTag = (mCurFilters.size() > 0) ? mCurFilters.at(oldFilterRow) : "null";//获取旧Tag文本
//更新文件内容
updateFile(mLogCacheFilePath);
//恢复更新文件前的相关显示参数
if(oldFilterRow >= lwFilter->count()) {
oldFilterRow = lwFilter->count() - 1;
oldFilterRow = (oldFilterRow > 0) ? oldFilterRow : 0;
} else {
int size = mCurFilters.size();
for (int i = 0; i < size; ++i) {
if (mCurFilters.at(i) == oldFilterTag) {
oldFilterRow = i;
break;
}
}
}
QObject::disconnect(ui->lwFilter,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(filterChangedSlot()));
if (lwFilter->count() > 0) {
if (oldFilterRow < lwFilter->count()) {
lwFilter->setCurrentRow(oldFilterRow);
} else {
lwFilter->setCurrentRow(0);
}
}
dispContainSearchString(ui->etSearch->text());
QObject::connect(ui->lwFilter,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(filterChangedSlot()));
int max = lwFilter->verticalScrollBar()->maximum();
if(oldFilterScrollPosition > max) {
oldFilterScrollPosition = max;
}
lwFilter->verticalScrollBar()->setValue(oldFilterScrollPosition);
//如果更新前显示的是最后一行,则表示实时显示最新内容;否则当前显示内容不变
if (isMax) {
ui->verticalScrollBar->setValue(ui->verticalScrollBar->maximum());
if (lwContent->count() > 0) {
isConnectScroll(false);
lwContent->setCurrentRow(lwContent->count() - 1);
isConnectScroll(true);
}
} else {
if(oldContentRow >= lwContent->count()) {
oldContentRow = lwContent->count() - 1;
oldContentRow = (oldContentRow > 0) ? oldContentRow : 0;
}
if (lwContent->count() > 0) {
isConnectScroll(false);
lwContent->setCurrentRow(oldContentRow);
isConnectScroll(true);
}
}
//如果当前打开了Tag分析窗口,则实时更新数据
if (mTagAnalyseDialog->isVisible() && (cnt >= 20)) {
cnt = 0;
QStringList tagList;
QStringList numList;
QString tag;
QString num;
QString text;
QStringList temp;
int size = lwFilter->count();
int length;
QListWidgetItem *item;
for (int i = 1; i < size; ++i) {
item = lwFilter->item(i);
if (item == NULL) {
continue;
}
text = item->text();
if (!text.contains("(") || !text.contains(")")) {
continue;
}
temp = text.split("(");
length = temp.length();
num = temp.at(length - 1).split(")").at(0);
tag = text.remove("(" + num + ")");
tagList.append(tag);
numList.append(num);
}
mTagAnalyseDialog->updateDisp(tagList,numList);
}
}
fileTimer->start(10);
}
/*
* 函数名称: statusTimeoutSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: ADB设备连接状态监控定时器槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::statusTimeoutSlot()
{
//如果正在检测系统进程PID,则不执行任何操作,避免造成冲突
if (isCheckingPID) {
return;
}
statusTimer->stop();
QString info = "";
//如果当前ADB设备连接成功了
if (isADBConnectedSuccess(mCurADBDevice)) {
if (mCurADBDevice == "") {
return;
}
//如果上一次是未连接状态,且当前是实时终端模式,则表示是重连接,
//需要通过手动模拟再次进入实时终端模式,以达到自动恢复显示的目的
if(!mCurADBDeviceStatus && isTerminalMode) {
isTerminalMode = false;
clickTerminalAction(); //执行该函数之前mCurADBDeviceStatus必须为false
}
mCurADBDeviceStatus = true;
info = "连接成功";
ledOn(LED_ID_ADB_STATUS);
isNeedBackupCacheFile = true;
mReConnecCnt = 0; //如果连接成功了,则清空重连计数器
} else {
mCurADBDeviceStatus = false;
fileTimer->stop();
//判断该设备是否还存在
if ((mCurADBDevice != "") && !isExistDevice(mCurADBDevice)) {
info = "设备丢失";
} else {
info = "连接断开";
}
ledOff(LED_ID_ADB_STATUS);
mCurDebugAppPID = "";
curDebugAppLabel->setText("");
//如果非人为退出实时终端模式,且ADB设备由连接变为断开,则需要对文件进行一次备份操作
if (!isPeopleExitTerminal && isNeedBackupCacheFile) {
QFile *file = new QFile(mLogCacheFilePath);
//如果日志缓存文件存在
if (file->exists()) {
//文件命名形如:xxx/xxx/cache/logCache-2.log
QString path = mLogCacheFilePath.split(".").at(0) + "-"
+ QString::number(mBackupCacheFilePath.size()) + ".log";
QFile saveFile(path);
//如果已经存在该文件,则先删除
if (saveFile.exists()) {
saveFile.remove();
}
//开始备份文件
if (file->copy(path)) {
mBackupCacheFilePath.append(path);
}
}
file->close();
delete file;
isNeedBackupCacheFile = false;
}
//如果重连3次均失败,则退出ADB环境
if (mReConnecCnt >= 3) {
mReConnecCnt = 0;
QMessageBox::information(this,"警告","3次重连失败,即将退出ADB环境!");
mCurADBDeviceStatus = false; //更新当前ADB设备的连接状态
statusTimer->stop(); //停止状态监控定时器
mCurADBDevice = ""; //清空当前设备名
adbDeviceLabel->clear(); //清空软件底部状态栏的显示
//如果当前处于实时终端模式
if (isTerminalMode) {
prepareChangeModeParams(false); //退出实时终端模式
}
}
}
//更新软件底部状态栏的显示
//adbDeviceLabel->setText(" 【当前ADB设备】: " + mCurADBDeviceName + " " + info + " ");
QFontMetrics elidFont(adbDeviceLabel->font());
adbDeviceLabel->setText(elidFont.elidedText(" 【当前ADB设备】: " + mCurADBDeviceName + " " + info + " ",
Qt::ElideMiddle,adbDeviceLabel->maximumWidth()));
statusTimer->start(1000);
}
/*
* 函数名称: eventLoopTimeoutSlot()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.15
* 函数功能: 主线程的事件循环控制定时器槽函数,仅执行一次
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::eventLoopTimeoutSlot()
{
mEventLoop->exit(); //退出事件阻塞,使主线程恢复执行
eventLoopTimer->stop(); //关闭该定时器,保证单次执行即可
}
/*******************************************************************************************
* Action动作函数区域
* *****************************************************************************************/
/*
* 函数名称: setingAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 设置菜单点击动作
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::setingAction()
{
//创建设置对话框并显示
Setting *dialog = new Setting;
dialog->transParams(mCurFontType,mCurFontSize,mCurCodeType,ADBPath,
isApplyOfflineMode,isApplyRealtimeMode,
isFirstFilter,isSecondFilter,isApplyDebugApp,mCurDebugApp);
dialog->exec();
//如果点击了确定按钮,则设置属性生效
if (dialog->getIsClickTrue()) {
QStringList paramList; //创建存储参数表
bool isNeedUpdateFont = false; //是否需要更新字体
bool isNeedReloadFile = false; //是否需要重载文件
//判断当前字体类型是否有变化
if (mCurFontType != dialog->getFontType()) {
isNeedUpdateFont = true;
mCurFontType = dialog->getFontType();
paramList.append(mSettingParse->createParamsItem(FONT_TYPE,mCurFontType));
}
//判断当前字体大小是否有变化
if (mCurFontSize != dialog->getFontSize()) {
isNeedUpdateFont = true;
mCurFontSize = dialog->getFontSize();
paramList.append(mSettingParse->createParamsItem(FONT_SIZE,QString::number(mCurFontSize)));
}
//判断是否需要更新字体
if (isNeedUpdateFont) {
QFont font = QFont(mCurFontType,mCurFontSize,QFont::Normal);
lwFilter->setFont(font);
lwContent->setFont(font);
labelTime->setFont(font);
labelLevel->setFont(font);
labelPID->setFont(font);
labelText->setFont(font);
labelTag->setFont(font);
autoAdjustTitleLabel();//自动调节标题标签的位置
}
//判断当前ADB路径是否有变化
if (ADBPath != dialog->getADBPath()) {
ADBPath = dialog->getADBPath();
paramList.append(mSettingParse->createParamsItem(ADB_PATH,ADBPath));
}
//判断当前是否启用调试指定APP功能是否有变化
if (isApplyDebugApp != dialog->getIsApplyDebugApp()) {
isApplyDebugApp = dialog->getIsApplyDebugApp();
paramList.append(mSettingParse->createParamsItem(IS_APPLY_DEBUG_APP,
(isApplyDebugApp) ? "true" : "false"));
}
if (isApplyDebugApp) {
mCurDebugApp = dialog->getCurDebugApp();
paramList.append(mSettingParse->createParamsItem(CUR_DEBUG_APP,mCurDebugApp));
}
//如果编码格式发生了变化则重新加载当前日志文件
if (mCurCodeType != dialog->getCodeType()) {
mCurCodeType = dialog->getCodeType();
paramList.append(mSettingParse->createParamsItem(CODE_TYPE,mCurCodeType));
//如果当前有文件打开,则需要重载文件
if (!mCurLogFilePath.isEmpty()) {
isNeedReloadFile = true;
}
}
//如果系统过滤级别发生了变化
if ((isFirstFilter != dialog->getIsFirstFilter())
|| (isSecondFilter != dialog->getIsSecondFilter())) {
isFirstFilter = dialog->getIsFirstFilter();
isSecondFilter = dialog->getIsSecondFilter();
paramList.append(mSettingParse->createParamsItem(IS_FIRST_SYS_FILTER,
(isFirstFilter) ? "true" : "false"));
paramList.append(mSettingParse->createParamsItem(IS_SECOND_SYS_FILTER,
(isSecondFilter) ? "true" : "false"));
mFirstSysFilters = dialog->getFirstSysFilters();
mSecondSysFilters = dialog->getSecondSysFilters();
QString lint = SEPARATOR;
QString temp = "";
int size = mFirstSysFilters.size();
for (int i = 0; i < size - 1; ++i) {
temp += mFirstSysFilters.at(i) + lint;
}
if (size > 0) {
temp += mFirstSysFilters.at(size - 1);
}
paramList.append(mSettingParse->createParamsItem(FIRST_SYS_FILTERS,temp));
temp = "";
size = mSecondSysFilters.size();
for (int i = 0; i < size - 1; ++i) {
temp += mSecondSysFilters.at(i) + lint;
}
if (size > 0) {
temp += mSecondSysFilters.at(size - 1);
}
paramList.append(mSettingParse->createParamsItem(SECOND_SYS_FILTERS,temp));
//如果当前有文件打开,则需要重载文件
if (!mCurLogFilePath.isEmpty()) {
isNeedReloadFile = true;
}
}
//如果系统过滤应用模式发生了变化
if ((isApplyOfflineMode != dialog->getIsApplyOfflineMode())
|| (isApplyRealtimeMode != dialog->getIsApplyRealtimeMode())) {
isApplyOfflineMode = dialog->getIsApplyOfflineMode();
isApplyRealtimeMode = dialog->getIsApplyRealtimeMode();
paramList.append(mSettingParse->createParamsItem(IS_APPLY_OFFLINE_MODE,
(isApplyOfflineMode) ? "true" : "false"));
paramList.append(mSettingParse->createParamsItem(IS_APPLY_REALTIME_MODE,
(isApplyRealtimeMode) ? "true" : "false"));
//如果当前有文件打开,则需要重载文件
if (!mCurLogFilePath.isEmpty()) {
isNeedReloadFile = true;
}
}
//如果需要重载文件
if (isNeedReloadFile) {
//如果当前是实时模式,则需要手动将该标志位置位,否则无法自动完整显示所有内容
if (isTerminalMode) {
mFilterChangedFlag = true;
}
refreshLogFileAction();
//如果当前是实时终端模式,显示内容的最后一行,以便达到显示最新内容的目的
if (isTerminalMode) {
ui->verticalScrollBar->setValue(ui->verticalScrollBar->maximum());
if (lwContent->count() > 0) {
lwContent->setCurrentRow(lwContent->count() - 1);
}
}
}
//将新的设置更新到设置文件中
bool isSaveSuccess = mSettingParse->saveParamsToFile(mSettingFilePath,paramList);
if (isSaveSuccess) {
logCurTime("保存配置参数成功!");
} else {
logCurTime("保存配置参数失败!");
}
}
delete dialog;
}
/*
* 函数名称: openFileAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 打开文件菜单点击动作
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::openFileAction()
{
//打开后缀为*.txt的日志文件
QString path = QFileDialog::getOpenFileName(this,"请选择LogCat文件",
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),"(*.txt *.log)");
//logCurTime("path=" + path);
//如果选择某一路径后点击了确定按钮
if (!path.isEmpty()) {
resetPageParams();
loadFile(path); //加载该文件
}
}
/*
* 函数名称: closeFileAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 关闭文件菜单点击动作,释放相应的资源
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::closeFileAction()
{
ui->verticalScrollBar->setHidden(true);
ui->etSearch->clear();
//ui->cbLevel->setCurrentIndex(0);
lwContent->clear();
ui->swTimeFilter->setChecked(false);
mCurLogFilePath = "";
fileLabel->clear();
clearAllDataList();
resetPageParams();
}
/*
* 函数名称: aboutAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.6
* 函数功能: 关于软件动作
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::aboutAction()
{
aboutSoftware *dialog = new aboutSoftware;
dialog->exec();
delete dialog;
}
/*
* 函数名称: refreshLogFileAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 重载当前日志文件槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::refreshLogFileAction()
{
if (mCurLogFilePath.isEmpty()) {
QMessageBox::information(this,"警告","当前无文件打开,无法重载!");
return;
}
resetPageParams();
loadFile(mCurLogFilePath);
}
/*
* 函数名称: clickTerminalAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: 终端模式开关槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::clickTerminalAction()
{
//如果当前是实时终端模式
if (isTerminalMode) {
//如果确认退出实时终端模式
if (QMessageBox::Ok == QMessageBox::information(this,"警告","是否要退出终端模式?"
,QMessageBox::Ok,QMessageBox::Cancel)) {
isPeopleExitTerminal = true;
//关闭日志缓存文件大小监控定时器
if (fileTimer->isActive()) {
logCurTime("fileTimer is Active");
fileTimer->stop();
}
//关闭CMD进程
if (cmdProcess != NULL) {
logCurTime("!=NULL");
if (cmdProcess->Running) {
logCurTime("Running");
cmdProcess->close();
cmdProcess->kill();
cmdProcess = NULL;
delete cmdProcess;
}
}
prepareChangeModeParams(false); //退出实时终端模式
}
}
//如果当前是离线查看模式
else {
//ADBPath = "D:/ruanjain/工具类/ADB调试";
//如果设置了ADB工具路径
if (ADBPath != "") {
//当前是否连接了ADB设备
if (mCurADBDevice != "") {
//先判断日志缓存路径是否存在,若不存在则立即创建该路径
if (!isDirExist(mLogCacheFilePath,true)) {
QMessageBox::information(this,"警告","创建日志缓存文件失败,无法进入实时终端模式!");
return;
}
//创建CMD进程,用于将Android日志输出到指定文件
cmdProcess = new QProcess(this);
cmdProcess->setProcessChannelMode(QProcess::MergedChannels);
cmdProcess->setWorkingDirectory(ADBPath); //必须设置正确的进程工作路径,否则将找不到ADB工具
//如果已经存在日志缓存文件,则获取其大小,否则该大小默认为0
QFile *file = new QFile(mLogCacheFilePath);
if (file->exists()) {
logFileSize = file->size();
} else {
logFileSize = 0;
}
file->close();
delete file;
//清空日志输出的缓存
QString cmd = "adb -s " + mCurADBDevice + " logcat -c";
//此处if的目的是:当显示过程中ADB设备连接突然断开或丢失后再次重连时,不需要清空缓存
if (mCurADBDeviceStatus) {
cmdProcess->start("cmd",QStringList()<<"/c"<<cmd);
cmdProcess->waitForStarted();
cmdProcess->waitForFinished();
}
//开始重新输出日志到指定文件
// cmd = "adb -s " + mCurADBDevice + " logcat -b main -v time -s TableView>"
// + mLogCacheFilePath;
cmd = "adb -s " + mCurADBDevice + " logcat -v time>"
+ mLogCacheFilePath;
cmdProcess->reset();
cmdProcess->start("cmd",QStringList()<<"/c"<<cmd);
prepareChangeModeParams(true); //进入实时终端模式
} else {
QMessageBox::information(this,"警告","请先选择一个ADB设备!");
}
} else {
QMessageBox::information(this,"警告","未设置ADB工具路径,请检查!");
}
}
}
/*
* 函数名称: connectADBAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: 连接或断开ADB设备槽函数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::connectADBAction()
{
//如果当前ADB设备是连接状态
if (mCurADBDeviceStatus) {
//如果确认断开当前ADB连接
if (QMessageBox::Ok == QMessageBox::information(this,"警告","是否要断开当前ADB连接?"
,QMessageBox::Ok,QMessageBox::Cancel)) {
isPeopleExitTerminal = true;
//如果当前处于实时终端模式
if (isTerminalMode) {
prepareChangeModeParams(false); //退出实时终端模式
}
isNeedBackupCacheFile = false;
mCurADBDeviceStatus = false; //更新当前ADB设备的连接状态
statusTimer->stop(); //停止状态监控定时器
mCurADBDevice = ""; //清空当前设备名
adbDeviceLabel->setText(NO_ADB_DEVICE); //清空软件底部状态栏的显示
ledOff(LED_ID_ADB_STATUS);
statusTimeoutSlot();
}
}
//如果当前ADB设备未连接,且未正在扫描ADB设备
else if (!isScaningADBDevice) {
isScaningADBDevice = true;
//ADBPath = "D:/ruanjain/工具类/ADB调试";
//如果设置了ADB工具路径
if (ADBPath != "") {
adbDeviceLabel->setText(" 正在扫描ADB设备.... ");
QStringList result = execWindowsCmd(ADBPath,"adb start-server");//启动ADB服务器
if (!result.at(0).isEmpty() && !result.at(0).contains("successfully")) {
isScaningADBDevice = false;
QMessageBox::information(this,"警告","ADB路径错误,请重新设置!");
return;
}
QStringList deviceNames = getCurOnlineDeviceNames(); //获取当前在线的ADB设备表
//如果有设备存在
if (deviceNames.size() != 0) {
adbDeviceLabel->setText(" 扫描完成,发现了" + QString::number(deviceNames.size()) + "个设备 ");
//创建并显示设备选择对话框
ConnectADB *dialog = new ConnectADB;
dialog->transParams(deviceNames);
dialog->exec(); //阻塞式,直到用户点击了按钮返回
//如果点击了确定
if (dialog->getIsClickTrue()) {
mCurADBDevice = dialog->getDeviceName(); //获取当前选中的设备串号
QString info = "";
if (mCurADBDevice == "") {
mCurADBDeviceStatus = false;
info = "无设备";
}
//判断该设备是否连接成功
if (isADBConnectedSuccess(mCurADBDevice)) {
statusTimer->start(1000); //启动ADB设备连接状态监控定时器(1s监测一次)
mCurADBDeviceStatus = true;
info = "连接成功";
ledOn(LED_ID_ADB_STATUS);
} else {
mCurADBDeviceStatus = false;
info = "连接失败";
}
//更新软件底部的状态栏显示
QString name = "null";
QString manufacture = "";
QString type = "";
QString temp;
for (int i = 0; i < deviceNames.size(); ++i) {
temp = deviceNames.at(i);
if (temp.contains(mCurADBDevice)) {
if (temp.split(DEVICE_NAME_SEPERATE).size() == 1) {
name = temp;
} else if (temp.split(DEVICE_NAME_SEPERATE).size() == 5) {
manufacture = temp.split(DEVICE_NAME_SEPERATE).at(0);
type = temp.split(DEVICE_NAME_SEPERATE).at(1);
name = manufacture + "-" + type;
} else {
name = temp;
}
break;
}
}
if ((name == "") || (name == "-")) {
name = mCurADBDevice;
} else if (name.startsWith("-")) {
name += mCurADBDevice;
} else if (name.endsWith("-")) {
name = name.remove(0,1) + "-" + mCurADBDevice;
}
mCurADBDeviceName = name;
//adbDeviceLabel->setText(" 【当前ADB设备】: " + mCurADBDeviceName + " " + info + " ");
QFontMetrics elidFont(adbDeviceLabel->font());
adbDeviceLabel->setText(elidFont.elidedText(" 【当前ADB设备】: " + mCurADBDeviceName + " " + info + " ",
Qt::ElideMiddle,adbDeviceLabel->maximumWidth()));
} else {
adbDeviceLabel->clear();
}
delete dialog;
} else {
QMessageBox::information(this,"警告","未发现设备");
adbDeviceLabel->setText(NO_ADB_DEVICE);
}
} else {
QMessageBox::information(this,"警告","请先设置ADB工具路径,再进行连接!");
}
isScaningADBDevice = false;
}
}
/*
* 函数名称: gotoLineAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.16
* 函数功能: 跳转到行
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::gotoLineAction()
{
if (mCurLogFilePath.isEmpty()) {
QMessageBox::information(this,"警告","当前无文件打开,无法进行行跳转!");
return;
}
QVBoxLayout *vLayout = new QVBoxLayout;
QHBoxLayout *hLayout1 = new QHBoxLayout;
QHBoxLayout *hLayout2 = new QHBoxLayout;
QHBoxLayout *hLayout3 = new QHBoxLayout;
QLabel *label1 = new QLabel("当前行范围:1~" + QString::number(mCurLines));
hLayout1->addWidget(label1);
QLabel *label2 = new QLabel("跳转到行:");
QLineEdit *edit = new QLineEdit;
hLayout2->addWidget(label2);
hLayout2->addWidget(edit);
QPushButton *btnOK = new QPushButton("OK");
QPushButton *btnCancel = new QPushButton("Cancel");
hLayout3->addWidget(btnOK);
hLayout3->addWidget(btnCancel);
vLayout->addLayout(hLayout1);
vLayout->addLayout(hLayout2);
vLayout->addLayout(hLayout3);
QDialog *dialog = new QDialog;
dialog->setWindowTitle("跳转到行");
dialog->setLayout(vLayout);
dialog->adjustSize(); //调整对话框尺寸,使其刚好容纳所有子控件
dialog->setFixedSize(dialog->size()); //固定窗口大小
QObject::connect(edit,SIGNAL(textChanged(QString)),this,SLOT(gotoLineEditTextChangedSLot(QString)));
QObject::connect(btnCancel,SIGNAL(clicked()),dialog,SLOT(close()));
QObject::connect(btnOK,SIGNAL(clicked()),this,SLOT(gotoLineSlot()));
mCurOptDialog = dialog;
dialog->exec();
delete dialog;
}
/*
* 函数名称: registerSolftwareAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.16
* 函数功能: 注册软件动作
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::registerSolftwareAction()
{
Security *security = Security::getInstance();
if (security->isRegisted()) {
QMessageBox::information(this,"提示","软件已注册,注册码为:" + mRegisterNum);
} else {
//创建注册对话框并显示
Register *dialog = new Register;
dialog->exec();
//如果点击了确定按钮且注册成功了
if (dialog->getIsClickTrue()) {
mRegisterNum = dialog->getRegisterNum();
mSettingParse->saveRegisterNumToFile(mSettingFilePath,mRegisterNum);
}
delete dialog;
}
}
/*
* 函数名称: backupSettingFileAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.19
* 函数功能: 备份配置文件
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::backupSettingFileAction()
{
if (isTerminalMode) {
QMessageBox::information(this,"警告","无法在实时终端模式下备份,请先退出该模式!");
return;
}
QString oldPath = mSettingFilePath;
QString newPath = mSettingFilePath.split(SETTING_FILE_PATH).at(0) + BACKUP_SETTING_FILE_PATH;
//备份原先的文件
QString temp = mSettingFilePath.split(SETTING_FILE_PATH).at(0) + TEMP_SETTING_FILE_PATH;
if (!QFile::copy(oldPath,temp)) {
QMessageBox::information(this,"提示","备份失败!");
return;
}
//如果已经存在备份文件,则先删除
QFile file(newPath);
if (file.exists()) {
file.remove();
}
if (QFile::copy(oldPath,newPath)) {
QMessageBox::information(this,"提示","备份成功!");
} else {
QFile::copy(temp,newPath); //若备份失败,则恢复原先的文件
QMessageBox::information(this,"提示","备份失败!");
}
//删除临时文件
QFile tempFile(temp);
if (tempFile.exists()) {
tempFile.remove();
}
}
/*
* 函数名称: importSettingFileAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.19
* 函数功能: 导入配置文件
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::importSettingFileAction()
{
if (isTerminalMode) {
QMessageBox::information(this,"警告","无法在实时终端模式下导入,请先退出该模式!");
return;
}
QString temp = SETTING_FILE_PATH;
QString path = QFileDialog::getOpenFileName(this,"请选择要导入的配置文件",
mWindowsUserPath + "/" + temp.split("/").at(1),"(*.cfg)");
if (!path.isEmpty()) {
if (!mSettingParse->checkFile(path)) {
QMessageBox::information(this,"警告","该配置文件无法被软件识别,请检查配置文件格式是否符合规范!");
return;
}
//备份原先的文件
temp = mSettingFilePath.split(SETTING_FILE_PATH).at(0) + TEMP_SETTING_FILE_PATH;
if (!QFile::copy(mSettingFilePath,temp)) {
QMessageBox::information(this,"提示","导入失败!");
return;
}
//先删除原先的配置文件
QFile file(mSettingFilePath);
if (file.exists()) {
file.remove();
}
if (QFile::copy(path,mSettingFilePath)) {
//加载软件的设置文件,并设置相应的参数
loadSoftwareSetting(mSettingFilePath);
if (!mCurLogFilePath.isEmpty()) {
QFont font = QFont(mCurFontType,mCurFontSize,QFont::Normal);
lwFilter->setFont(font);
lwContent->setFont(font);
labelTime->setFont(font);
labelLevel->setFont(font);
labelPID->setFont(font);
labelText->setFont(font);
labelTag->setFont(font);
autoAdjustTitleLabel();//自动调节标题标签的位置
if (!mCurLogFilePath.isEmpty()) {
refreshLogFileAction();
}
}
QMessageBox::information(this,"提示","导入成功!");
} else {
QFile::copy(temp,mSettingFilePath); //若导入失败,则恢复原先的文件
QMessageBox::information(this,"提示","导入失败!");
}
//删除临时文件
QFile tempFile(temp);
if (tempFile.exists()) {
tempFile.remove();
}
}
}
/*
* 函数名称: nextPageAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.2
* 函数功能: 跳转到下一页
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::nextPageAction()
{
mCurPageIndex++;
if (mCurPageIndex >= MAX_PAGE_NUM) {
mCurPageIndex = MAX_PAGE_NUM - 1;
}
loadFile(mCurLogFilePath);
}
/*
* 函数名称: lastPageAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.3
* 函数功能: 跳转到上一页
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::lastPageAction()
{
mCurPageIndex--;
if (mCurPageIndex < 0) {
mCurPageIndex = 0;
}
loadFile(mCurLogFilePath);
}
/*
* 函数名称: pageOffsetAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.3
* 函数功能: 页分界切换
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::pageOffsetAction()
{
bool temp = isPageOffsetMode;
resetPageParams();
isPageOffsetMode = !temp;
loadFile(mCurLogFilePath);
}
/*
* 函数名称: openTagAnalyseWindowsAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.4
* 函数功能: 打开Tag分析窗口
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::openTagAnalyseWindowsAction()
{
if (mCurLogFilePath.isEmpty()) {
QMessageBox::information(this,"警告","当前无日志文件打开,无法分析Tag!");
return;
}
if (lwFilter->count() <= 0) {
QMessageBox::information(this,"警告","当前日志文件中无Tag,无法分析Tag!");
return;
}
QListWidgetItem *item = lwFilter->item(0);
if (item == NULL) {
return;
}
if ((lwFilter->count() == 1) && (lwFilter->item(0)->text().contains(DEFAULT_TAG))) {
QMessageBox::information(this,"警告","当前日志文件中仅有All messages,无法分析Tag!");
return;
}
QStringList tagList;
QStringList numList;
QString tag;
QString num;
QString text;
QStringList temp;
int size = lwFilter->count();
int length;
for (int i = 1; i < size; ++i) {
item = lwFilter->item(i);
if (item == NULL) {
continue;
}
text = item->text();
if (!text.contains("(") || !text.contains(")")) {
continue;
}
temp = text.split("(");
length = temp.length();
num = temp.at(length - 1).split(")").at(0);
tag = text.remove("(" + num + ")");
tagList.append(tag);
numList.append(num);
}
//创建设置对话框并显示
delete mTagAnalyseDialog;
mTagAnalyseDialog = new TagAnalyse;
mTagAnalyseDialog->transParams(tagList,numList);
mTagAnalyseDialog->show();
mTagAnalyseDialog->exec();
}
/*
* 函数名称: restartSoftwareAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.8
* 函数功能: 重启软件
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::restartSoftwareAction()
{
isClickRestart = true;
qApp->closeAllWindows();
}
/*
* 函数名称: clearCurDispAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.8
* 函数功能: 清空当前显示(实时模式下)
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::clearCurDispAction()
{
if (QMessageBox::Ok == QMessageBox::information(this,"警告",
"是否清空当前显示?",QMessageBox::Ok,QMessageBox::Cancel)) {
QString oldPID = ui->cbPID->currentText();
clearAllDataList();//清空当前显示
if (oldPID != "All") {
QObject::disconnect(ui->cbPID,SIGNAL(currentIndexChanged(int)),this,SLOT(cbPIDChangedSlot()));
ui->cbPID->addItem(oldPID);
ui->cbPID->setCurrentIndex(1);
QObject::connect(ui->cbPID,SIGNAL(currentIndexChanged(int)),this,SLOT(cbPIDChangedSlot()));
}
}
}
/*
* 函数名称: installAPKAction()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.6.5
* 函数功能: 安装APK到指定设备
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::installAPKAction()
{
//如果当前ADB设备处于连接状态
if (mCurADBDeviceStatus) {
//打开后缀为*.apk的日志文件
QString path = QFileDialog::getOpenFileName(this,"请选择APK文件",
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),"(*.apk)");
if (!path.isEmpty()) {
QString apkName = path.split("/").last();
bool isInstallSuccess = false;
int prePercent = 0;
QByteArray backup;
QString cmd = "adb -s " + mCurADBDevice + " install -r " + path;
QString out;
QString err;
bool existProgress = false;
QProcess process(0);
process.setWorkingDirectory(ADBPath);
process.start("cmd",QStringList()<<"/c"<<cmd);
process.waitForFinished(500);
backup = process.readAllStandardOutput();
out = QString::fromLocal8Bit(backup);
err = QString::fromLocal8Bit(process.readAllStandardError());
// logCurTime("【out】=" + out);
// logCurTime("【err】=" + err);
if (out.startsWith("[") && out.contains("%]") && !out.contains("adb: error:")) {
existProgress = true;
QStringList list = out.split("\n");
QString last;
QString current;
for (int i = 0; i < list.size(); ++i) {
if (list.at(i).startsWith("[") && list.at(i).contains("%]")) {
last = list.at(i);
current = last.mid(1,4);
while(current.contains(" ")) {
current.replace(" ","");
}
if (current.endsWith("%")) {
current = current.remove(current.length() - 1,1);
} else {
current = "";
}
}
}
if (stringIsNum(current)) {
prePercent = current.toInt();
} else {
prePercent = 0;
}
}
if ((err == "") && !out.contains("adb: error:") && (prePercent != 100)) {
//创建并显示加载进度条
QProgressDialog *progressDialog = new QProgressDialog;
progressDialog->setWindowFlags(Qt::FramelessWindowHint);
progressDialog->setCancelButton(0);
progressDialog->setLabelText("正在安装,请稍等....");
progressDialog->setMinimum(0);
progressDialog->setMaximum(100);
progressDialog->setModal(true);
progressDialog->setValue(prePercent);
mainThreadWait_ms(10); //阻塞主线程10ms,只有阻塞主线程,进度条才有机会显示出来
QString current; //当前已读取的大小
QString oldPercent; //记录上一次的百分比
QString last;
QStringList list;
while(true) {
out = QString::fromUtf8(process.readAllStandardOutput());
err = QString::fromUtf8(process.readAllStandardError());
if (existProgress) {
list = out.split("\n");
for (int i = 0; i < list.size(); ++i) {
if (list.at(i).startsWith("[") && list.at(i).contains("%]")) {
last = list.at(i);
current = last.mid(1,4);
while(current.contains(" ")) {
current.replace(" ","");
}
if (current.endsWith("%")) {
current = current.remove(current.length() - 1,1);
} else {
current = "";
}
}
}
//logCurTime("【last】=" + last);
//logCurTime("【out】=" + out);
//logCurTime("【err】=" + err);
//更新文件加载的进度条
if (oldPercent != current && stringIsNum(current)) {
progressDialog->setValue(current.toInt()); //设置进度条
oldPercent = current;
mainThreadWait_ms(1);
}
if (last.contains("[100%]")) {
isInstallSuccess = true;
progressDialog->close();
mainThreadWait_ms(1);
delete progressDialog;
break;
}
} else {
if (out.contains("Success") || err.contains("Success")) {
isInstallSuccess = true;
progressDialog->setValue(100);
mainThreadWait_ms(100);
progressDialog->close();
mainThreadWait_ms(1);
delete progressDialog;
break;
} else {
//logCurTime("等待...");
progressDialog->setValue(50);
mainThreadWait_ms(1);
}
}
if (err != "") {
progressDialog->close();
mainThreadWait_ms(1);
delete progressDialog;
break;
}
mainThreadWait_ms(500);
// statusTimeoutSlot();
if (!mCurADBDeviceStatus) {
progressDialog->close();
mainThreadWait_ms(1);
delete progressDialog;
break;
}
}
}
process.close();
process.kill();
if (isInstallSuccess || (prePercent == 100)) {
QMessageBox::information(this,"提示","应用【" + apkName + "】安装成功!");
} else {
if (!mCurADBDeviceStatus) {
QMessageBox::information(this,"提示","应用【" + apkName + "】安装失败,原因:设备连接断开!");
} else if (out.contains("adb: error:")) {
err = QString::fromUtf8(backup);
err = err.split("adb: error:").at(1);
QMessageBox::information(this,"提示","应用【" + apkName + "】安装失败!\n\n【err】:"
+ "该设备的Android系统版本过低,不支持中文APK名;\n" + err.trimmed());
} else {
QMessageBox::information(this,"提示","应用【" + apkName + "】安装失败!\n\n【err】:" + err.trimmed());
}
}
}
} else {
QMessageBox::information(this,"警告","请先连接ADB设备!");
}
}
/*******************************************************************************************
* 私有函数区域
* *****************************************************************************************/
/*
* 函数名称: closeEvent()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: 应用程序右上角X关闭触发事件
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::closeEvent(QCloseEvent *event)
{
//提醒用户是否退出软件,防止误操作使软件关闭而导致重要数据的丢失
if (QMessageBox::Ok == QMessageBox::information(this,"警告",
"是否退出软件?",QMessageBox::Ok,QMessageBox::Cancel)) {
event->accept(); //接收该事件,即允许退出软件
} else {
event->ignore(); //忽略该事件,即不允许退出软件
return;
}
//关闭ADB设备连接状态监控定时器
if (statusTimer->isActive()) {
statusTimer->stop();
}
//清空日志缓存文件(如果存在的话)
clearLogCacheFile();
//清空软件缓存目录(如果存在的话)
clearCachePath();
//保证在等待对话框关闭后再退出软件
while(1) {
mainThreadWait_ms(500);
if (!mWaitDialog->isVisible()) {
break;
}
}
if (isClickRestart) {
isClickRestart = false;
QProcess::startDetached(qApp->applicationFilePath(),QStringList());
}
}
/*
* 函数名称: clearLogCacheFile()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: 清空日志缓存文件(如果存在的话)
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::clearLogCacheFile()
{
killADBServer(); //立即关闭ADB服务
rebuildLogCacheFile(); //如果存在日志备份文件,则对其进行文件重构
QFile *file = new QFile(mLogCacheFilePath);
//如果日志缓存文件存在
if (file->exists()) {
//此处代码目的:避免用户误点击导致日志缓存文件被删除,在删除前添加了确认对话框
//用户是否先将缓存文件另存为
while (1) {
//如果需要将日志缓存文件另存为
if (QMessageBox::Ok == QMessageBox::information(this,"警告",
"是否保存日志缓存文件?"
,QMessageBox::Ok,QMessageBox::Cancel)) {
//设置要保存的路径和文件名
QString fileName = QFileDialog::getSaveFileName(this, "保存文件",
mLogCacheFilePath,"Text files (*.log)");
//如果设置了另存为的路径
if (!fileName.isEmpty()) {
QFile saveFile(fileName);
//如果已经存在该文件,则选择是否覆盖
if (saveFile.exists()) {
if (QMessageBox::Ok == QMessageBox::information(this,"警告",
"该文件已经存在,是否确定要覆盖?"
,QMessageBox::Ok,QMessageBox::Cancel)) {
saveFile.remove();
if (file->copy(fileName)) {
QMessageBox::information(this,"警告","保存成功!");
} else {
QMessageBox::information(this,"警告","保存失败!");
}
break;
}
} else {
if (file->copy(fileName)) {
QMessageBox::information(this,"警告","保存成功!");
} else {
QMessageBox::information(this,"警告","保存失败!");
}
break;
}
} else {
QMessageBox::information(this,"警告","另存为的文件名为空,请重新设置!");
}
}
//如果不需要保存日志缓存文件
else {
//再次提醒用户是否真的不需要保存,因为一旦该文件被删除,
//将无法再次回复,以免造成重要的调试信息因为误操作而丢失。
if (QMessageBox::Ok == QMessageBox::information(this,"警告",
"缓存文件即将被删除,是否确认?"
,QMessageBox::Ok,QMessageBox::Cancel)) {
break;
}
}
}
//删除日志缓存文件
file->close();
file->remove();
delete file;
}
}
/*
* 函数名称: clearCachePath()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.19
* 函数功能: 清空软件缓存目录(如果存在的话)
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::clearCachePath()
{
//如果软件缓存路径为空则删除缓存路径
QString dirName = QCoreApplication::applicationDirPath() + "/cache";
QDir dir(dirName);
QFileInfoList infoList = dir.entryInfoList(QDir::Dirs | QDir::Files);
int num = infoList.size();
for (int i = 0; i < num; ++i) {
if (infoList.at(i).isFile()) {
QFile file(infoList.at(i).absoluteFilePath());
file.remove();
}
}
if (dir.entryInfoList(QDir::Dirs | QDir::Files).count() <= 2) {
dir.rmdir(dirName);
}
}
/*
* 函数名称: clearCachePath()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.19
* 函数功能: 清空软件缓存目录(如果存在的话)
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::ledOn(int id)
{
isLedOn = true;
switch (id) {
case LED_ID_ADB_STATUS:
adbStatusLabel->setStyleSheet("border-image: url(:/new/image/ledon.png);");
break;
default:
isLedOn = false;
break;
}
}
/*
* 函数名称: clearCachePath()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.19
* 函数功能: 清空软件缓存目录(如果存在的话)
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::ledOff(int id)
{
isLedOn = false;
switch (id) {
case LED_ID_ADB_STATUS:
adbStatusLabel->setStyleSheet("border-image: url(:/new/image/ledoff.png);");
break;
default:
break;
}
}
/*
* 函数名称: updateCurFilters()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.21
* 函数功能: 更新当前选中的PID号对应的信息
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::updateCurFilters()
{
long time = QDateTime::currentMSecsSinceEpoch();
QString curPID = ui->cbPID->currentText();
if (curPID == "All") {
mCurFilters = mAllFilters;
mCurFiltersNums = mAllFiltersNums;
} else {
int num;
int cnt;
QString tag;
mCurFilters.clear();
mCurFiltersNums.clear();
for (int i = 0; i < mAllLines; ++i) {
if (curPID == mAllPIDs.at(i)) {
tag = mAllTags.at(i);
if (!mCurFilters.contains(tag)) {
mCurFilters.append(tag);
mCurFiltersNums.append("0");
}
num = mCurFilters.size();
for (int j = 0; j < num; ++j) {
if (tag == mCurFilters.at(j)) {
cnt = mCurFiltersNums.at(j).toInt();
mCurFiltersNums.replace(j,QString::number(cnt + 1));
}
}
}
}
QString lint = "#*$*#";
num = mCurFilters.size();
QStringList tempList;
for (int i = 0; i < num; ++i) {
tempList.append(mCurFilters.at(i) + lint + mCurFiltersNums.at(i));
}
tempList.sort(Qt::CaseInsensitive);
//重构mCurFilters和mCurFiltersNums两个链表
mCurFilters.clear();
mCurFiltersNums.clear();
QStringList tempSplit;
for (int i = 0; i < num; ++i) {
tempSplit = tempList.at(i).split(lint);
mCurFilters.append(tempSplit.at(0));
mCurFiltersNums.append(tempSplit.at(1));
}
int sum = 0;
for (int i = 0; i < num; ++i) {
sum += mCurFiltersNums.at(i).toInt();
}
mCurFilters.insert(0,DEFAULT_TAG);
mCurFiltersNums.insert(0,QString::number(sum));
}
//计算每个TAG的数目并显示
lwFilter->reset();
lwFilter->clear();
int filterNum = mCurFilters.size();
QString text;
for (int i = 0; i < filterNum; ++i) {
if (curPID == "All") {
text = mAllFilters.at(i) + "(" + mAllFiltersNums.at(i) + ")";
} else {
//text = dispList.at(i);
text = mCurFilters.at(i) + "(" + mCurFiltersNums.at(i) + ")";
}
lwFilter->addItem(text);
QListWidgetItem *item = lwFilter->item(lwFilter->count() - 1);
if (item == NULL) {
continue;
}
item->setToolTip(text);
}
time = QDateTime::currentMSecsSinceEpoch() - time;
logCurTime("【进程切换耗时】" + QString::number(time) + "ms");
}
/*
* 函数名称: isBreakCurLine(QString text)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.28
* 函数功能: 判断是否跳过解析当前行
* 输入参数: text:要判断的文本内容
* 输出参数: 无
* 返回值: 需要跳过返回true,否则返回false
*/
bool MainWindow::isBreakCurLine(QString text)
{
//如果当前为离线查看模式,且系统过滤器不应用于该模式,则不跳过
if (!isTerminalMode && !isApplyOfflineMode) {
return false;
}
//如果当前为实时终端模式,且系统过滤器不应用于该模式,则不跳过
if (isTerminalMode && !isApplyRealtimeMode) {
return false;
}
//如果一级过滤和二级过滤都没应用,则不跳过
if (!isFirstFilter && !isSecondFilter) {
return false;
}
//获取所有需要过滤的Tag
QStringList filters;
if (isFirstFilter) {
for (int i = 0; i < mFirstSysFilters.size(); ++i) {
filters.append(mFirstSysFilters.at(i));
}
}
if (isSecondFilter) {
for (int i = 0; i < mSecondSysFilters.size(); ++i) {
filters.append(mSecondSysFilters.at(i));
}
}
//判断当前行文本内容中是否包含需要过滤的Tag
QString temp = text.split("): ").at(0);
int size = filters.size();
for (int i = 0; i < size; ++i) {
if (temp.contains(filters.at(i))) {
return true;
}
}
return false;
}
/*
* 函数名称: setSearchPercentValue(int percent)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.4.28
* 函数功能: 设置搜索进度百分比的值
* 输入参数: percent:要设置的百分比值
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::setSearchPercentValue(int percent)
{
if (!isSearching) {
return;
}
if (percent < 0) {
percent = 0;
}
if (percent > 100) {
percent = 100;
}
mSearchDialog->setValue(percent);
mainThreadWait_ms(1);
}
/*
* 函数名称: clearAllPageOffset
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.2
* 函数功能: 清空所有页的页偏移值
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::clearAllPageOffset()
{
for (int i = 0; i < MAX_PAGE_NUM; ++i) {
mAllPageOffset[i] = 0;
}
}
/*
* 函数名称: resetPageParams()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.2
* 函数功能: 重置页相关参数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::resetPageParams()
{
mCurPageIndex = 0;
mPageNum = 0;
isPageOffsetMode = false;
clearAllPageOffset();
ui->actionLastPage->setEnabled(false);
ui->actionNextPage->setEnabled(false);
ui->actionPageOffset->setEnabled(false);
//使页跳转控件隐藏
ui->labelPage->setHidden(true);
ui->cbPage->setHidden(true);
QObject::disconnect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
ui->cbPage->clear();
QObject::connect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
}
/*
* 函数名称: getFileSeperatorNum(QTextStream in)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.3
* 函数功能: 获取一个文件中换行符所占的字节数
* 输入参数: in:文件流
* 输出参数: 无
* 返回值: 返回文件中换行符所占的字节数
*/
int MainWindow::getFileSeperatorNum(QString path)
{
int num = 0;
QString buff;
QFile file(path);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::information(this,"警告","获取文件换行符占用字节数失败,文件可能不存在!");
return num;
}
QTextStream in(&file);
in.seek(0);
while(!in.atEnd()) {
buff = in.readLine();
num = in.pos() - buff.toUtf8().length();
break;
}
in.seek(0);
file.close();
num = (num >= 0) ? num : 0;
return num;
}
/*
* 函数名称: resetChangeModeParams()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.3
* 函数功能: 重置模式切换时的相关参数
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::resetChangeModeParams()
{
isCheckedUpdateFile = false; //设置文件为规范性未检查
mLastPos = 0; //设置上一次的文件光标位置为0
closeFileAction(); //关闭加载的日志缓存文件
}
/*
* 函数名称: prepareChangeModeParams(bool isTerminal)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.3
* 函数功能: 切换软件工作模式时的参数准备
* 输入参数: isTerminal:当前是否为实时终端模式
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::prepareChangeModeParams(bool isTerminal)
{
//进入实时终端模式
if (isTerminal) {
//失能部分控件
ui->actionOpen->setEnabled(false);
ui->actionRefresh->setEnabled(false);
ui->history->setEnabled(false);
ui->actionGotoLine->setEnabled(false);
ui->actionClearCurDisp->setEnabled(true);
ui->actionClose->setEnabled(false);
//使页跳转控件隐藏
ui->labelPage->setHidden(true);
ui->cbPage->setHidden(true);
QObject::disconnect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
ui->cbPage->clear();
QObject::connect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
isTerminalMode = true; //更新当前工作模式状态
ui->etSearch->setEnabled(false);
resetChangeModeParams(); //重置模式切换时的相关参数
//启动日志缓存文件大小监控定时器(10ms检测一次是否有变化)
fileTimer->start(10);
workModeLabel->setText(WORK_MODE_ONLINE);
QObject::disconnect(ui->cbPID,SIGNAL(currentIndexChanged(int)),this,SLOT(cbPIDChangedSlot()));
}
//进入离线查看模式
else {
//使能部分控件
ui->actionOpen->setEnabled(true);
ui->actionRefresh->setEnabled(true);
ui->history->setEnabled(true);
ui->actionGotoLine->setEnabled(true);
ui->actionClearCurDisp->setEnabled(false);
ui->actionClose->setEnabled(true);
isTerminalMode = false; //更新当前工作模式状态
ui->etSearch->setEnabled(true);
resetChangeModeParams(); //重置模式切换时的相关参数
clearLogCacheFile(); //清空日志缓存文件
isPeopleExitTerminal = false;
workModeLabel->setText(WORK_MODE_OFFLINE);
QObject::connect(ui->cbPID,SIGNAL(currentIndexChanged(int)),this,SLOT(cbPIDChangedSlot()));
}
}
/*
* 函数名称: stringIsNum(QString str)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.3
* 函数功能: 判断一个字符串是否可以转换为数字
* 输入参数: str:要判断的字符串
* 输出参数: 无
* 返回值: 可以转换返回true,否则返回false
*/
bool MainWindow::stringIsNum(QString str)
{
if (str.isEmpty()) {
return false;
}
QChar temp;
for (int i = 0; i < str.length(); ++i) {
temp = str.at(i);
if ((temp < '0') || (temp > '9')) {
return false;
}
}
return true;
}
/*
* 函数名称: rebuildLogCacheFile()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.3
* 函数功能: 重构日志缓存文件
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::rebuildLogCacheFile()
{
QFile *file;
int num = mBackupCacheFilePath.size();
if (num > 0) {
logCurTime("正在重构日志缓存文件......");
//创建并显示重构进度条
QProgressDialog *progressDialog = new QProgressDialog;
progressDialog->setWindowFlags(Qt::FramelessWindowHint);
progressDialog->setCancelButton(0);
progressDialog->setLabelText("正在重构日志文件....");
progressDialog->setMinimum(0);
progressDialog->setMaximum(100);
progressDialog->setValue(0);
progressDialog->setModal(true);
progressDialog->show();
mainThreadWait_ms(10); //阻塞主线程10ms,只有阻塞主线程,进度条才有机会显示出来
int percent = 0;
int oldPercent = 0;
//构建日志备份文件的路径
QString newPath = QCoreApplication::applicationDirPath() + LOG_REBUILD_FILE_PATH;
QFile outFile(newPath);
//如果已存在,则删除
if (outFile.exists()) {
outFile.remove();
}
//如果文件打开成功(若不存在则会自动创建,因为是只写的方式打开的)
if(outFile.open(QIODevice::WriteOnly | QIODevice::Text))
{
//创建文件输出流
QTextStream out(&outFile);
out.setCodec(QTextCodec::codecForName(QString("UTF-8").toLatin1()));
QString path;
QString buff;
QStringList logList;
QString oldTime = "00-00 00:00:00.000";
QString newTime;
QString oldText = "";
QStringList sameList; //两个文件之间头尾相同的部分
bool isHandleSame = false; //是否处理了头尾相同的部分
//如果存在本身的缓存文件,则参与分析重构
file = new QFile(mLogCacheFilePath);
if (file->exists()) {
mBackupCacheFilePath.append(mLogCacheFilePath);
num += 1;
}
delete file;
int max[num];
int sum = 0;
int tempMax = 0;
for (int i = 0; i < num; ++i) {
tempMax = (int)((float)(900 * 1.0 / num));
sum += tempMax;
max[i] = tempMax;
}
tempMax = 0;
max[num - 1] = max[num - 1] + 900 - sum;
//开始分析重构
for (int i = 0; i < num; ++i) {
path = mBackupCacheFilePath.at(i);
file = new QFile(path);
//logCurTime("size[" + path + "]=" + QString::number(file->size()));
//以只读的方式打开文件
if(file->open(QIODevice::ReadOnly | QIODevice::Text))
{
//创建读取输入流
QTextStream in(file);
in.setCodec(QTextCodec::codecForName(QString("UTF-8").toLatin1()));
tempMax += (i > 0) ? max[i - 1] : 0;
long fileSize = file->size(); //文件总大小
long curSize = 0;
int seperatorNum = getFileSeperatorNum(path);
sameList.clear();
isHandleSame = false;
while(!in.atEnd()) {
buff = in.readLine();
curSize += buff.toUtf8().length() + seperatorNum;
//更新文件加载的进度条
percent = (int)(max[i] * (float)(curSize * 1.0 / fileSize)) + tempMax;
percent = (percent > (max[i] + tempMax)) ? (max[i] + tempMax) : percent;
percent /= 10;
if (oldPercent != percent) {
progressDialog->setValue(percent); //设置进度条
oldPercent = percent;
mainThreadWait_ms(1);
}
if (checkLogCatFile(buff)) {
logList = textToList(reConstruction);
newTime = logList.at(0);
int result = QString::compare(newTime,oldTime);
//如果还未处理头尾相同部分,则必须先处理这部分(即过滤掉相同的部分)
if (!isHandleSame) {
if (result < 0) {
continue;
} else if (result == 0) {
sameList.append(buff);
continue;
} else {
for (int j = 0; j < sameList.size(); ++j) {
if (!isHandleSame && (sameList.at(j) == oldText)) {
isHandleSame = true;
continue;
} else if (isHandleSame) {
out<<sameList.at(j)<<"\n";
oldText = sameList.at(j);
}
}
isHandleSame = true;
}
}
//如果新的时间大于旧的时间戳,或者等于且新旧文本不相同
if ((result > 0) || ((result == 0) && (oldText != buff))) {
out<<buff<<"\n";
}
oldTime = newTime;
oldText = buff;
}
}
//添加文件分隔符,便于分析观察,无实际用处
if (i != (num - 1)) {
QString seperator = "-------------------------文件重构分隔符--------------------------";
out<<seperator<<"\n";
}
file->close();//注意:此处文件必须关闭,否则后面将无法删除文件
delete file;
} else {
QMessageBox::information(this,"警告","重构文件失败,无法打开备份文件!");
progressDialog->close();
mainThreadWait_ms(10);
delete progressDialog;
return;
}
}
outFile.close();//重构完毕,关闭输出流
sum = 0;
for (int i = 0; i < num; ++i) {
tempMax = (int)((float)(100 * 1.0 / num));
sum += tempMax;
max[i] = tempMax;
}
max[num - 1] = max[num - 1] + 100 - sum;
tempMax = 900;
//删除备份文件和缓存文件(如果存在)
for (int i = 0; i < num; ++i) {
path = mBackupCacheFilePath.at(i);
file = new QFile(path);
file->remove();
delete file;
//更新文件加载的进度条
tempMax += (i > 0) ? max[i - 1] : 0;
percent = (int)(max[i] * (float)((i + 1) * 1.0 / num)) + tempMax;
percent = (percent > (max[i] + tempMax)) ? (max[i] + tempMax) : percent;
percent /= 10;
if (oldPercent != percent) {
progressDialog->setValue(percent); //设置进度条
oldPercent = percent;
mainThreadWait_ms(1);
}
}
//将重构文件复制为缓存文件,然后删除重构文件
if (outFile.copy(mLogCacheFilePath)) {
mBackupCacheFilePath.clear();
outFile.remove();
progressDialog->setValue(100);
mainThreadWait_ms(1);
} else {
while (1) {
//如果需要将日志缓存文件另存为
if (QMessageBox::Ok == QMessageBox::information(this,"警告",
"缓存文件被其他进程占用,无法复制,是否将重构文件复制到其他位置?"
,QMessageBox::Ok,QMessageBox::Cancel)) {
//设置要保存的路径和文件名
QString fileName = QFileDialog::getSaveFileName(this, "保存文件",
newPath,"Text files (*.log)");
//如果设置了另存为的路径
if (!fileName.isEmpty()) {
QFile saveFile(fileName);
//如果已经存在该文件,则选择是否覆盖
if (saveFile.exists()) {
if (QMessageBox::Ok == QMessageBox::information(this,"警告",
"该文件已经存在,是否确定要覆盖?"
,QMessageBox::Ok,QMessageBox::Cancel)) {
saveFile.remove();
if (outFile.copy(fileName)) {
QMessageBox::information(this,"警告","保存成功!");
} else {
QMessageBox::information(this,"警告","保存失败!");
}
mBackupCacheFilePath.clear();
outFile.remove();
break;
}
} else {
if (outFile.copy(fileName)) {
QMessageBox::information(this,"警告","保存成功!");
} else {
QMessageBox::information(this,"警告","保存失败!");
}
mBackupCacheFilePath.clear();
outFile.remove();
break;
}
} else {
QMessageBox::information(this,"警告","另存为的文件名为空,请重新设置!");
}
}
//如果不需要保存日志重构文件
else {
//再次提醒用户是否真的不需要保存,因为一旦该文件被删除,
//将无法再次回复,以免造成重要的调试信息因为误操作而丢失。
if (QMessageBox::Ok == QMessageBox::information(this,"警告",
"重构文件即将被删除,是否确认?"
,QMessageBox::Ok,QMessageBox::Cancel)) {
mBackupCacheFilePath.clear();
outFile.remove();
break;
}
}
}
}
logCurTime("重构完毕");
} else {
QMessageBox::information(this,"警告","重构文件失败,无法创建重构文件!");
}
progressDialog->close();
mainThreadWait_ms(10);
delete progressDialog;
}
}
/*
* 函数名称: killADBServer()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.5.5
* 函数功能: 立即关闭ADB服务器
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::killADBServer()
{
QProcess process(0);
process.setWorkingDirectory(ADBPath);
process.start("cmd",QStringList()<<"/c"<<"adb kill-server");
process.waitForStarted();
process.waitForFinished(500);
process.close();
process.kill();
}
/*
* 函数名称: exitTerminalMode()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.6.26
* 函数功能: 强制退出实时终端模式
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::exitTerminalMode()
{
isPeopleExitTerminal = true;
//关闭日志缓存文件大小监控定时器
if (fileTimer->isActive()) {
logCurTime("fileTimer is Active");
fileTimer->stop();
}
//关闭CMD进程
if (cmdProcess != NULL) {
logCurTime("!=NULL");
if (cmdProcess->Running) {
logCurTime("Running");
cmdProcess->close();
cmdProcess->kill();
cmdProcess = NULL;
delete cmdProcess;
}
}
prepareChangeModeParams(false); //退出实时终端模式
}
/*
* 函数名称: execWindowsCmd(QString adbPath,QString cmd)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: 执行CMD命令
* 输入参数: adbPath:ADB工具路径 cmd:要执行的命令
* 输出参数: 无
* 返回值: 返回字符串列表,包含两个元素,其中[0]:表示执行结果返回; [1]:表示执行错误返回
*/
/*QStringList MainWindow::execWindowsCmd(QString adbPath,QString cmd)
{
QStringList result;
if (adbPath == "") {
result.append("");
result.append("未设置ADB路径");
return result;
}
QProcess process(0);
process.setWorkingDirectory(adbPath);
process.start("cmd",QStringList()<<"/c"<<cmd);
process.waitForStarted();
process.waitForFinished(5000);
QString out = QString::fromUtf8(process.readAllStandardOutput());
QString err = QString::fromUtf8(process.readAllStandardError());
process.close();
process.kill();
out = out.trimmed();
err = err.trimmed();
result.append(out);
result.append(err);
return result;
}*/
/*
* 函数名称: execWindowsCmd(QString adbPath,QString cmd)
* 函数版本: 2.0.0
* 作者: HXL
* 创建日期: 2017.3.13
* 函数功能: 执行CMD命令,该版本为通过启动一个后台线程去执行,避免耗时等待阻塞UI线程
* 输入参数: adbPath:ADB工具路径 cmd:要执行的命令
* 输出参数: 无
* 返回值: 返回字符串列表,包含两个元素,其中[0]:表示执行结果返回; [1]:表示执行错误返回
*/
QStringList MainWindow::execWindowsCmd(QString adbPath,QString cmd)
{
QStringList result;
if (mEventLoop->isRunning()) {
logCurTime("已有事件在运行,命令【" + cmd + "】执行失败!");
}
if (!isStartADBServer) {
isStartADBServer = true;
}
//创建执行ADB命令的线程,并建立相关的信号与槽的连接
ADBThread *thread = new ADBThread(this);
QObject::connect(thread,SIGNAL(done()),this,SLOT(threadDoneSlot()));
QObject::connect(thread,SIGNAL(showDialog()),this,SLOT(showDialogSlot()));
QObject::connect(thread,SIGNAL(closeDialog()),this,SLOT(closeDialogSlot()));
thread->transParams(adbPath,cmd); //必须先向该线程传入执行参数
thread->start(); //启动线程
//mEventLoop->exec(); //将主线程阻塞,以便等待ADB线程的命令执行完毕
isExitEventLoop = false;
while(!isExitEventLoop) {
//QCoreApplication::processEvents(QEventLoop::AllEvents,10000);
mainThreadWait_ms(20);
}
result = thread->getResult(); //获取ADB命令执行的结果
delete thread;
return result;
}
/*
* 函数名称: isADBConnectedSuccess(QString deviceName)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: 判断某个ADB设备是否连接成功
* 输入参数: deviceName:设备名
* 输出参数: 无
* 返回值: 连接成功返回true,否则返回false
*/
bool MainWindow::isADBConnectedSuccess(QString deviceName)
{
if ((deviceName == "") || !isExistDevice(deviceName)) {
return false;
}
//判断方式:通过执行shell命令"pwd"打印当前路径,若返回"/"则表示连接成功
QStringList result = execWindowsCmd(ADBPath,"adb -s " + deviceName + " shell pwd");
// logCurTime("【out】" + result.at(0));
// logCurTime("【err】" + result.at(1));
if (result.at(1).startsWith(ADB_ERR_RESULT)) {
return false;
}
if (result.at(0) == "/") {
return true;
} else {
return false;
}
}
/*
* 函数名称: getCurOnlineDeviceNames()
* 函数版本: 1.0.0
* 函数版本: 2.0.0 【增加ADB设备厂商、型号、系统版本以及SDK版本的获取显示功能】
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: 获取当前在线的ADB设备
* 输入参数: 无
* 输出参数: 无
* 返回值: 返回在线的设备名列表
*/
QStringList MainWindow::getCurOnlineDeviceNames()
{
QStringList result = execWindowsCmd(ADBPath,"adb devices");
QString out = result.at(0);
if (out.contains("List of devices attached")) {
QStringList devices = out.split("\n");
if (devices.size() > 1) {
QStringList tempList;
int size;
QStringList deviceNames;
QString info;
QString serial;
QString manufacturer;
QString name;
QString version;
QString sdk;
int parseStep;
for (int i = 1; i < devices.size(); ++i) {
manufacturer = "";
name = "";
version = "";
sdk = "";
serial = "";
QString temp = devices.at(i);
if (temp.contains("device") && (!temp.contains("List of devices attached"))) {
serial = temp.remove(temp.length() - 7,7);
result = execWindowsCmd(ADBPath,"adb -s " + serial + " shell cat /system/build.prop");
if (!result.at(0).isEmpty()) {
tempList = result.at(0).split("\n");
size = tempList.size();
parseStep = 0;
for (int i = 0; i < size; ++i) {
temp = tempList.at(i);
if (temp.contains("ro.product.manufacturer=")) {
manufacturer = temp.split("=").at(1).trimmed();
manufacturer.replace("-","_");
parseStep++;
} else if (temp.contains("ro.product.model=")) {
name = temp.split("=").at(1).trimmed();
name.replace("-","_");
parseStep++;
} else if (temp.contains("ro.build.version.release=")) {
version = temp.split("=").at(1).trimmed();
version.replace("-","_");
parseStep++;
} else if (temp.contains("ro.build.version.sdk=")) {
sdk = temp.split("=").at(1).trimmed();
sdk.replace("-","_");
parseStep++;
}
if (parseStep >= 4) {
break;
}
}
info = manufacturer + DEVICE_NAME_SEPERATE + name + DEVICE_NAME_SEPERATE + version + DEVICE_NAME_SEPERATE + sdk + DEVICE_NAME_SEPERATE + serial;
} else {
info = serial;
}
deviceNames.append(info);
}
}
if (deviceNames.size() > 0) {
return deviceNames;
}
}
}
QStringList temp;
return temp;
}
/*
* 函数名称: isExistDevice(QString deviceName)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.16
* 函数功能: 判断某个ADB设备名是否存在
* 输入参数: deviceName:ADB设备名
* 输出参数: 无
* 返回值: 若存在则返回true,否则返回false
*/
bool MainWindow::isExistDevice(QString deviceName)
{
QStringList deviceNames = getCurOnlineDeviceNames();
for (int i = 0; i < deviceNames.size(); ++i) {
if (deviceNames.at(i).contains(deviceName)) {
return true;
}
}
return false;
}
/*
* 函数名称: logCurTime(QString text)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.10
* 函数功能: 带时间戳的调试打印
* 输入参数: text:要打印的内容
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::logCurTime(QString text)
{
//如果调试开关打开了,则打印信息,否则不进行打印
#if DEBUG_SWITCH
qDebug()<<"【" + QDateTime::currentDateTime().toString("hh:mm:ss.zzz") + "】" + text;
#endif
}
/*
* 函数名称: updateCurRange()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.10
* 函数功能: 更新当前显示缓冲区的范围
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::updateCurRange()
{
if (lwFilter->count() > 0) {
int visibleHeight = lwContent->height(); //获取内容显示区的总高度
int itemHeight = lwFilter->sizeHintForRow(0); //获取一行所占的高度
int visibleItemNum = visibleHeight / itemHeight;//计算可完整显示的行数
if (visibleItemNum < 0) {
visibleItemNum = 0;
}
//更新当前显示缓冲区范围
int first = mCurRange->getFirst();
int visibleFirst = mCurRange->getVisibleFirst();
int count = visibleItemNum + visibleItemNum / 2;
delete mCurRange;
mCurRange = new ItemsRange(this,first,visibleFirst,count,visibleItemNum,mCurLevels.size());
// logCurTime("mVisibleHeight=" + QString::number(visibleHeight));
// logCurTime("mItemHeight=" + QString::number(itemHeight));
// logCurTime("mVisibleItemNum=" + QString::number(mCurRange->getPageItemNum()));
// logCurTime("first=" + QString::number(mCurRange->getFirst()));
// logCurTime("visibleFirst=" + QString::number(mCurRange->getVisibleFirst()));
// logCurTime("last=" + QString::number(mCurRange->getLast()));
}
}
/*
* 函数名称: loadFile(QString path)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 加载一个日志文件
* 输入参数: path:文件的绝对路径
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::loadFile(QString path)
{
//如果已经有文件正在加载中,则不执行任何操作
if (isLoadingFile) {
return;
}
isLoadingFile = true;
mLogType = LOG_TYPE_UNKNOWN;
logCurTime("开始加载文件....");
//打开文件
QFile logFile(path);
if(!logFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::information(this,"警告","读取文件失败,该文件可能不存在,请检查路径!");
isLoadingFile = false;
return;
}
//创建并显示加载进度条
QProgressDialog *progressDialog = new QProgressDialog;
progressDialog->setCancelButton(0);
progressDialog->setLabelText("正在加载文件....");
progressDialog->setMinimum(0);
progressDialog->setMaximum(100);
progressDialog->setValue(0);
progressDialog->setModal(true);
progressDialog->show();
mainThreadWait_ms(10); //阻塞主线程10ms,只有阻塞主线程,进度条才有机会显示出来
long fileSize = logFile.size(); //文件总大小
long curSize = 0; //当前已读取的大小
int oldPercent = 0; //记录上一次的百分比
int percent = 0; //当前进度的百分比
int curLines = 0; //当前已解析并可显示的行数
logCurTime("开始读取文件....");
long time = QDateTime::currentMSecsSinceEpoch();
long startTime = time;
//开始读取文件内容
QTextStream in(&logFile);
in.setCodec(QTextCodec::codecForName(mCurCodeType.toLatin1()));
QString buff;
bool isChecked = false;
if (!in.seek(mAllPageOffset[mCurPageIndex])) {
QMessageBox::information(this,"警告","文件寻址失败!");
isLoadingFile = false;
return;
}
int seperatorNum = getFileSeperatorNum(path);
while(!in.atEnd()) {
buff = in.readLine();
curSize += buff.toUtf8().length() + seperatorNum;//更新当前已读取的大小
//更新文件加载的进度条
curLines = (isChecked == true) ? mAllTags.size() : 0;
if (fileSize < MAX_CACHE_FILE_SIZE) {
percent = (int)(100 * (float)(curSize * 1.0 / fileSize));
} else {
percent = (int)(100 * (float)(curLines * 1.0 / MAX_CACHE_LINES));
}
percent = (percent > 100) ? 100 : percent;
if (oldPercent != percent) {
if (!progressDialog->isVisible()) {
closeFileAction();
isLoadingFile = false;
logCurTime("退出文件加载");
return;
}
progressDialog->setValue(percent); //设置进度条
oldPercent = percent;
mainThreadWait_ms(1);
}
//判断是否跳过解析改行内容,此处由系通过滤决定
if (isBreakCurLine(buff)) {
continue;
}
//如果还未对文件进行过规范性检查
if(!isChecked)
{
//进行规范性检查,判断是否为Android的日志文件
if(checkLogCatFile(buff))
{
isChecked = true;
mCurLogFilePath = path;
// fileLabel->setText(" 【当前日志文件路径】: " + mCurLogFilePath
// + " 第" + QString::number(mCurPageIndex + 1) + "页"
// + ((isPageOffsetMode == true) ? "(页分界偏移模式)" : "") + " ");
QFontMetrics elidFont(fileLabel->font());
fileLabel->setText(elidFont.elidedText(" 【当前日志文件路径】: " + mCurLogFilePath
+ " 第" + QString::number(mCurPageIndex + 1) + "页"
+ ((isPageOffsetMode == true) ? "(页分界偏移模式)" : "") + " ",
Qt::ElideMiddle,fileLabel->maximumWidth()));
clearAllDataList(); //初始化相关变量
//mFilters.append(DEFAULT_TAG); //添加默认的过滤器
} else {
continue;
}
} else {
if(!checkLogCatFile(buff))
{
continue;
}
}
//存储新的日志Tag
QStringList logList = textToList(reConstruction);
QString tag = logList.at(3);
if (!mAllFilters.contains(tag)) {
mAllFilters.append(tag);
}
//存储新的进程PID号
QString pid = logList.at(2);
if (!mPIDTypes.contains(pid)) {
mPIDTypes.append(pid);
ui->cbPID->addItem(pid);
}
//添加到全局数据表中
addItemToDataList(logList);
//判断是否为页分界偏移模式
if (!isPageOffsetMode) {
//如果已解析的行数达到了最大行数,且未到文件末尾
if ((mAllTags.size() == MAX_CACHE_LINES) && (curSize != fileSize)) {
if ((mCurPageIndex + 2) > mPageNum) {
mPageNum = mCurPageIndex + 2;
ui->actionPageOffset->setEnabled(true);
mAllPageOffset[mCurPageIndex + 1] = mAllPageOffset[mCurPageIndex] + curSize;
//使页跳转控件可见
ui->labelPage->setHidden(false);
ui->cbPage->setHidden(false);
QObject::disconnect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
if (ui->cbPage->count() == 0) {
ui->cbPage->addItem("第1页");
}
ui->cbPage->addItem("第" + QString::number(mPageNum) + "页");
QObject::connect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
}
break;
}
} else {
//页分界偏移模式,即整体偏移量移动半页
int tempLines = 0;
if (mCurPageIndex == 0) {
tempLines = MAX_CACHE_LINES / 2;
} else {
tempLines = MAX_CACHE_LINES;
}
if ((mAllTags.size() == tempLines) && (curSize != fileSize)) {
if ((mCurPageIndex + 2) > mPageNum) {
mPageNum = mCurPageIndex + 2;
ui->actionPageOffset->setEnabled(true);
mAllPageOffset[mCurPageIndex + 1] = mAllPageOffset[mCurPageIndex] + curSize;
//使页跳转控件可见
ui->labelPage->setHidden(false);
ui->cbPage->setHidden(false);
QObject::disconnect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
if (ui->cbPage->count() == 0) {
ui->cbPage->addItem("第1页");
}
ui->cbPage->addItem("第" + QString::number(mPageNum) + "页");
QObject::connect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
}
break;
}
}
}
//控制下一页的按钮使能状态
if (mCurPageIndex < (mPageNum - 1)) {
ui->actionNextPage->setEnabled(true);
} else {
ui->actionNextPage->setEnabled(false);
}
//控制上一页的按钮使能状态
if (mCurPageIndex > 0) {
ui->actionLastPage->setEnabled(true);
} else {
ui->actionLastPage->setEnabled(false);
}
mAllLines = mAllTags.size();
progressDialog->setValue(100);
mainThreadWait_ms(1);
//对数据解析后识别出来的所有Tag进行重新排序
if ((mAllFilters.size() > 0) && (mAllFilters.at(0).contains(DEFAULT_TAG))) {
mAllFilters.removeAt(0);
}
mAllFilters.sort(Qt::CaseInsensitive);
mAllFilters.insert(0,DEFAULT_TAG);
logCurTime("读取文件完毕");
time = QDateTime::currentMSecsSinceEpoch() - time;
logCurTime("【读取文件耗时】" + QString::number(time) + "ms");
logFile.close();
logCurTime("关闭文件");
if (!isChecked) {
QMessageBox::information(this,"警告","解析LogCat文件失败,此文件可能不是LogCat文件!");
progressDialog->close();
isLoadingFile = false;
delete progressDialog;
return;
}
logCurTime("开始构建TAG....");
time = QDateTime::currentMSecsSinceEpoch();
//计算每个TAG的数目并显示
mCurFilters = mAllFilters;
int filterNum = mCurFilters.size();
int tagNum = mAllLines;
int count = 0;
QString text;
QString temp;
text = DEFAULT_TAG;
mAllFiltersNums.clear();
mAllFiltersNums.append(QString::number(tagNum));
text += "(" + QString::number(tagNum) + ")";
lwFilter->addItem(text);
QListWidgetItem *item = lwFilter->item(lwFilter->count() - 1);
if (item == NULL) {
QMessageBox::information(this,"警告","解析LogCat文件失败,无法获取Filter栏指定对象!");
progressDialog->close();
isLoadingFile = false;
delete progressDialog;
return;
}
item->setToolTip(text);
for (int i = 1; i < filterNum; ++i) {
count = 0;
temp = mCurFilters.at(i);
for (int j = 0; j < tagNum; ++j) {
if (temp == mAllTags.at(j)) {
count++;
}
}
mAllFiltersNums.append(QString::number(count));
text = temp + "(" + QString::number(count) + ")";
lwFilter->addItem(text);
item = lwFilter->item(lwFilter->count() - 1);
if (item == NULL) {
QMessageBox::information(this,"警告","解析LogCat文件失败,无法获取Filter栏指定对象!");
progressDialog->close();
isLoadingFile = false;
delete progressDialog;
return;
}
item->setToolTip(text);
}
logCurTime("构建TAG完毕");
time = QDateTime::currentMSecsSinceEpoch() - time;
logCurTime("【构建TAG耗时】" + QString::number(time) + "ms");
ui->swTimeFilter->setChecked(false);//加载文件后,设置时间过滤器为失能状态
//最后默认选中第一行,并显示所有日志内容
time = QDateTime::currentMSecsSinceEpoch();
QObject::disconnect(ui->lwFilter,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(filterChangedSlot()));
if (lwFilter->count() > 0) {
lwFilter->setCurrentRow(0);
}
updateCurRange();
QObject::connect(ui->lwFilter,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(filterChangedSlot()));
time = QDateTime::currentMSecsSinceEpoch() - time;
logCurTime("【设置当前行耗时】" + QString::number(time) + "ms");
logCurTime("开始显示日志....");
time = QDateTime::currentMSecsSinceEpoch();
dispContainSearchString(ui->etSearch->text());
logCurTime("显示完毕");
time = QDateTime::currentMSecsSinceEpoch() - time;
logCurTime("【显示日志耗时】" + QString::number(time) + "ms");
startTime = QDateTime::currentMSecsSinceEpoch() - startTime;
logCurTime("【****************加载一次显示耗时】" + QString::number(startTime) + "ms");
//将打开的文件路径添加到历史记录中
addHistoryAction(path);
//设置页跳转控件的当前选项
QObject::disconnect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
ui->cbPage->setCurrentIndex(mCurPageIndex);
QObject::connect(ui->cbPage,SIGNAL(currentIndexChanged(int)),this,SLOT(gotoPageSlot()));
//清空正在加载文件的标志位
isLoadingFile = false;
//关闭加载进度框
progressDialog->close();
mainThreadWait_ms(10);
delete progressDialog;
}
/*
* 函数名称: updateFile(QString path)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.10
* 函数功能: 更新一个日志文件的内容
* 输入参数: path:文件路径
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::updateFile(QString path)
{
logCurTime("开始加载文件....");
QFile logFile(path);
if(!logFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::information(this,"警告","读取文件失败!");
exitTerminalMode();
return;
}
logCurTime("开始读取文件....");
long time = QDateTime::currentMSecsSinceEpoch();
long startTime = time;
//开始读取文件内容
QTextStream in(&logFile);
in.setCodec(QTextCodec::codecForName(mCurCodeType.toLatin1()));
QString buff;
//计算上一次已经加载的光标位置
long lastPos = mLastPos;
if (!in.seek(lastPos)) {
QMessageBox::information(this,"警告","文件寻址失败!");
exitTerminalMode();
return;
}
//在文件加载前,创建Tag(num)链表
QString lint = "#*$*#";
int size = mAllFilters.size();
if (size != mAllFiltersNums.size()) {
exitTerminalMode();
return;
}
QStringList tempList;
for (int i = 0; i < size; ++i) {
tempList.append(mAllFilters.at(i) + lint + mAllFiltersNums.at(i));
}
int seperatorNum = getFileSeperatorNum(path);
while(!in.atEnd()) {
buff = in.readLine();
mLastPos += buff.toUtf8().length() + seperatorNum;
//判断是否跳过解析改行内容,此处由系通过滤决定
if (isBreakCurLine(buff)) {
continue;
}
//如果还未对文件进行过规范性检查
if(!isCheckedUpdateFile)
{
//进行规范性检查,判断是否为Android的日志文件
if(checkLogCatFile(buff))
{
isCheckedUpdateFile = true;
mCurLogFilePath = path;
//fileLabel->setText(" 【当前日志文件路径】: " + mCurLogFilePath + " ");
fileLabel->setText("");
// QFontMetrics elidFont(fileLabel->font());
// fileLabel->setText(elidFont.elidedText(" 【当前日志文件路径】: " + mCurLogFilePath
// + " 第" + QString::number(mCurPageIndex + 1) + "页"
// + ((isPageOffsetMode == true) ? "(页分界偏移模式)" : "") + " ",
// Qt::ElideMiddle,fileLabel->maximumWidth()));
clearAllDataList(); //初始化相关变量
//mAllFilters.append(DEFAULT_TAG); //添加默认的过滤器
} else {
continue;
}
} else {
if(!checkLogCatFile(buff))
{
continue;
}
}
//存储新的日志Tag
QStringList logList = textToList(reConstruction);
QString tag = logList.at(3);
if (!mAllFilters.contains(tag)) {
mAllFilters.append(tag);
}
//存储新的进程PID号
QString pid = logList.at(2);
if (!mPIDTypes.contains(pid)) {
mPIDTypes.append(pid);
ui->cbPID->addItem(pid);
}
//添加到全局数据表中
addItemToDataList(logList);
//如果已加载的行数达到了最大行数,则清空全局数据缓冲区,避免时间长久造成的大量内存占用
if (mAllTags.size() == MAX_TERNIMAL_CACHE_LINES) {
closeFileAction();
return;
}
}
logCurTime("读取文件完毕");
time = QDateTime::currentMSecsSinceEpoch() - time;
logCurTime("【读取文件耗时】" + QString::number(time) + "ms");
logFile.close();
logCurTime("关闭文件");
//更新显示时如果检查不合格,不需要弹出提示框
// if (!isCheckedUpdateFile) {
// QMessageBox::information(this,"警告","解析LogCat文件失败,此文件可能不是LogCat文件!");
// return;
// }
logCurTime("开始构建TAG....");
time = QDateTime::currentMSecsSinceEpoch();
//根据新增的内容,更新每个Tag的当前数量
int oldAllLines = mAllLines;
mAllLines = mAllTags.size();
mAddNewLines = mAllLines - oldAllLines;
QString tempTag;
QStringList tempSplit;
int tempNum;
int tempIndex;
for (int i = 0; i < mAddNewLines; ++i) {
tempTag = mAllTags.at(oldAllLines + i);
tempNum = 0;
for (int j = 0; j < tempList.size(); ++j) {
tempNum = 0;
tempSplit = tempList.at(j).split(lint);
if (tempTag == tempSplit.at(0)) {
tempIndex = j;
tempNum = tempSplit.at(1).toInt() + 1;
break;
}
}
if (tempNum == 0) {
tempList.append(tempTag + lint + QString::number(1));
} else {
tempList.replace(tempIndex,tempTag + lint + QString::number(tempNum));
}
}
//对数据解析后识别出来的所有Tag进行重新排序
if ((tempList.size() > 0) && (tempList.at(0).contains(DEFAULT_TAG))) {
tempList.removeAt(0);
}
tempList.sort(Qt::CaseInsensitive);
tempList.insert(0,DEFAULT_TAG + lint + QString::number(mAllLines));
size = mAllFilters.size();
//判断解析器识别出来的总Tag数与更新后重构Tag(num)链表的数目是否相等
//若不相等,则表示数据更新错误
if (size > 0) {
if (mAllFilters.at(0).contains(DEFAULT_TAG)) {
if (size != tempList.size()) {
QMessageBox::information(this,"警告","Tag构建失败!");
exitTerminalMode();
return;
}
} else {
if ((size + 1) != tempList.size()) {
QMessageBox::information(this,"警告","Tag构建失败!");
exitTerminalMode();
return;
}
}
}
//重构mAllFilters和mAllFiltersNums两个链表
mAllFilters.clear();
mAllFiltersNums.clear();
for (int i = 0; i < size; ++i) {
tempSplit = tempList.at(i).split(lint);
mAllFilters.append(tempSplit.at(0));
mAllFiltersNums.append(tempSplit.at(1));
}
//将新的Tag种类及对应的数目显示到Filters栏
lwFilter->reset();
lwFilter->clear();
mCurFilters = mAllFilters;
int filterNum = mCurFilters.size();
QString text;
for (int i = 0; i < filterNum; ++i) {
text = mCurFilters.at(i) + "(" + mAllFiltersNums.at(i) + ")";
lwFilter->addItem(text);
}
//进程PID号筛选
updateCurFilters();
logCurTime("构建TAG完毕");
time = QDateTime::currentMSecsSinceEpoch() - time;
logCurTime("【构建TAG耗时】" + QString::number(time) + "ms");
ui->swTimeFilter->setChecked(false);//加载文件后,设置时间过滤器为失能状态
//最后默认选中第一行,并显示所有日志内容
time = QDateTime::currentMSecsSinceEpoch();
QObject::disconnect(ui->lwFilter,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(filterChangedSlot()));
if (lwFilter->count() > 0) {
lwFilter->setCurrentRow(0);
}
//updateCurRange();
QObject::connect(ui->lwFilter,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(filterChangedSlot()));
time = QDateTime::currentMSecsSinceEpoch() - time;
logCurTime("【设置当前行耗时】" + QString::number(time) + "ms");
// logCurTime("开始显示日志....");
// time = QDateTime::currentMSecsSinceEpoch();
// dispContainSearchString(ui->etSearch->text());
// logCurTime("显示完毕");
// time = QDateTime::currentMSecsSinceEpoch() - time;
// logCurTime("【显示日志耗时】" + QString::number(time) + "ms");
startTime = QDateTime::currentMSecsSinceEpoch() - startTime;
logCurTime("【****************加载一次显示耗时】" + QString::number(startTime) + "ms");
}
/*
* 函数名称: isTimeString(QString str)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 判断一个字符串是否为时间字符串
* 输入参数: str:要判断的字符串
* 输出参数: 无
* 返回值: 是的返回true,否则返回false
*/
bool MainWindow::isTimeString(QString str)
{
//时间字符串的格式为:"01-01 00:00:00.000"
QStringList tempStrList = str.split(" ");
if (tempStrList.length() != 2) {
return false;
}
if (!tempStrList[0].contains("-") || (tempStrList[0].length() != 5)) {
return false;
}
tempStrList = tempStrList[1].split(":");
if (tempStrList.length() != 3) {
return false;
}
if (!tempStrList[2].contains(".") || (tempStrList[2].length() != 6)) {
return false;
}
return true;
}
/*
* 函数名称: updateTimeStringToWidget(QString startTime, QString stopTime)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 将起止时间更新到控件显示
* 输入参数: startTime:起始时间 stopTime:终止时间
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::updateTimeStringToWidget(QString startTime, QString stopTime)
{
if (isTimeString(startTime) && isTimeString(stopTime)) {
QStringList tempList = startTime.split(" ");
QStringList tempList1 = tempList[0].split("-");
QStringList tempList2 = tempList[1].split(":");
QStringList tempList3 = tempList2[2].split(".");
QString startMonth = tempList1[0];
QString startDay = tempList1[1];
QString startHour = tempList2[0];
QString startMinute = tempList2[1];
QString startSecond = tempList3[0];
tempList = stopTime.split(" ");
tempList1 = tempList[0].split("-");
tempList2 = tempList[1].split(":");
tempList3 = tempList2[2].split(".");
QString stopMonth = tempList1[0];
QString stopDay = tempList1[1];
QString stopHour = tempList2[0];
QString stopMinute = tempList2[1];
QString stopSecond = tempList3[0];
//如果毫秒数不为0,则将时间秒加一
if (QString::compare(tempList3[1],"000") != 0) {
QDateTime date = QDateTime::fromString(stopTime.split(".")[0],"MM-dd hh:mm:ss");
QString tempStr = date.addSecs(1).toString("MM-dd hh:mm:ss");
stopSecond = tempStr.split(":")[2];
}
isConnectTimeFilter(false); //断开时间过滤器的信号与槽的连接
ui->cbStartMonth->setCurrentIndex(ui->cbStartMonth->findText(startMonth));
ui->cbStartDay->setCurrentIndex(ui->cbStartDay->findText(startDay));
ui->cbStartHour->setCurrentIndex(ui->cbStartHour->findText(startHour));
ui->cbStartMinute->setCurrentIndex(ui->cbStartMinute->findText(startMinute));
ui->cbStartSecond->setCurrentIndex(ui->cbStartSecond->findText(startSecond));
ui->cbStopMonth->setCurrentIndex(ui->cbStopMonth->findText(stopMonth));
ui->cbStopDay->setCurrentIndex(ui->cbStopDay->findText(stopDay));
ui->cbStopHour->setCurrentIndex(ui->cbStopHour->findText(stopHour));
ui->cbStopMinute->setCurrentIndex(ui->cbStopMinute->findText(stopMinute));
ui->cbStopSecond->setCurrentIndex(ui->cbStopSecond->findText(stopSecond));
isConnectTimeFilter(true); //建立时间过滤器的信号与槽的连接
}
}
/*
* 函数名称: dispContainSearchString(QString str)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 显示包含搜索栏信息的所有日志信息
* 输入参数: str:要搜索的字符串信息
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::dispContainSearchString(QString str)
{
if (mAllLines > 0) {
//加载大于等于某一日志等级且指定Tag的所有日志信息
loadLevelMessage(ui->cbLevel->currentText(), mCurFilters.at(ui->lwFilter->currentRow()));
int percentMax = 0;
int prePercent = 40;//用于搜索进程,前面已经进行的占比40%
int cnt = 0;
int total = mCurTexts.size();
int oldPercent = 0;
if (ui->swTimeFilter->isChecked()) {
//用于搜索进程,该处占比30%
percentMax = 30;
cnt = 0;
for (int i = 0; i < mCurTexts.size(); ++i) {
//将不属于起止时间范围的日志从当前数据表中移除
if (!isContainTime(mCurTimes.at(i))) {
mCurTimes.removeAt(i);
mCurLevels.removeAt(i);
mCurPIDs.removeAt(i);
mCurTags.removeAt(i);
mCurTexts.removeAt(i);
i--;
}
cnt++;
//如果当前为离线查看模式,且正处于搜索进程中
if (!isTerminalMode && isSearching) {
if (isExitSearch) {
return;
}
int percent = (int)(percentMax * cnt / total);
if (oldPercent != percent) {
setSearchPercentValue(prePercent + percent);
}
oldPercent = percent;
}
}
}
//如果存在搜索字符串
if (str != "") {
percentMax = (percentMax == 30) ? 30 : 60;
prePercent = (percentMax == 30) ? 70 : 40;
cnt = 0;
for (int i = 0; i < mCurTexts.size(); ++i) {
//将不包含搜索条件的日志从当前数据表中移除
if (!isContainString(mCurTexts.at(i),str)) {
mCurTimes.removeAt(i);
mCurLevels.removeAt(i);
mCurPIDs.removeAt(i);
mCurTags.removeAt(i);
mCurTexts.removeAt(i);
i--;
}
cnt++;
//如果当前为离线查看模式,且正处于搜索进程中
if (!isTerminalMode && isSearching) {
if (isExitSearch) {
return;
}
int percent = (int)(percentMax * cnt / total);
if (oldPercent != percent) {
setSearchPercentValue(prePercent + percent);
}
oldPercent = percent;
}
}
}
mCurLines = mCurTags.size();
updateCurRange(); //更新当前显示缓冲区范围
//自动更新时间过滤器的起止时间显示
if (mCurTimes.isEmpty()) {
mStartTime = "01-01 00:00:00.000";
mStopTime = "01-01 00:00:00.000";
} else {
mStartTime = mCurTimes.at(0);
mStopTime = mCurTimes.at(mCurLines - 1);
}
updateTimeStringToWidget(mStartTime,mStopTime);
//显示当前数据表
dispCurDataList();
}
}
/*
* 函数名称: autoAdjustTitleLabel()
* 函数版本: 2.0.0
* 作者: HXL
* 创建日期: 2017.3.14
* 函数功能: 自动调节标签栏
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::autoAdjustTitleLabel()
{
if (mCurLines > 0) {
QFontMetrics fm(ui->lwContent->font());
QString space = ""; //控制偏移的空格数
//此处的6为固定的偏移,可视具体情况来调整
labelLine->setMinimumWidth(6 + fm.width(QString::number(mCurLines)));
labelLine->setMaximumWidth(6 + fm.width(QString::number(mCurLines)));
labelTime->setMinimumWidth(fm.width(" " + mCurTimes.at(0)));
labelTime->setMaximumWidth(fm.width(" " + mCurTimes.at(0)));
labelLevel->setMinimumWidth(fm.width(" " + mCurLevels.at(0) + " "));
labelLevel->setMaximumWidth(fm.width(" " + mCurLevels.at(0) + " "));
space = (isDispLevel) ? "" : " ";
labelPID->setMinimumWidth(fm.width(space + mCurPIDs.at(0)));
labelPID->setMaximumWidth(fm.width(space + mCurPIDs.at(0)));
if(isDispPID == isDispLevel) {
space = " ";
} else {
space = "";
}
labelTag->setMinimumWidth(fm.width(space + mCurTags.at(0)));
labelTag->setMaximumWidth(fm.width(space + mCurTags.at(0)));
}
}
/*
* 函数名称: intToString(int num, int bitNum)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 将int数字转换为固定位数的QString,位数不足的补0
* 输入参数: num:int型数字 bitNum:固定的位数
* 输出参数: 无
* 返回值: 返回转换后的字符串
*/
QString MainWindow::intToString(int num, int bitNum)
{
return QString::number(num).rightJustified(bitNum,'0');
}
/*
* 函数名称: checkLogCatFile(QString str)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 检查是否为Android的日志文件
* 输入参数: str:要检查的日志文件的第一行
* 输出参数: 无
* 返回值: 是的返回true,否则返回false
*/
bool MainWindow::checkLogCatFile(QString str)
{
if (mLogType == LOG_TYPE_UNKNOWN) {
parseLogType(str);
if (mLogType == LOG_TYPE_UNKNOWN) {
return false;
}
}
if (mLogType == LOG_TYPE_1) {
reConstruction.clear();
QString ori = str.split("): ").at(0);
if (ori == str) {
return false;
}
QString temp = ori;
temp = temp.remove(" ");
if (temp.length() < 22) {
return false;
}
if (":" == temp.at(17)) {
temp.remove(17,1);
}
temp.insert(5," ");
temp.insert(18," ");
reConstruction.append(temp.append("):"));
reConstruction.append(str.mid(ori.length() + 3));
QStringList list = temp.split(" ");
if ("-" != list.at(0).at(2)) {
reConstruction.clear();
return false;
}
int num = list.at(1).split(":").length();
if (num != 3) {
reConstruction.clear();
return false;
}
temp = list.at(2);
if ("/" != temp.at(1)) {
reConstruction.clear();
return false;
}
if (!QString("VDIWEAF").contains(temp.at(0))) {
reConstruction.clear();
return false;
}
if (!temp.remove(0,2).contains("(")) {
reConstruction.clear();
return false;
}
return true;
} else if (mLogType == LOG_TYPE_2) {
return checkLogCatFileV2(str);
}
}
/*
* 函数名称: checkLogCatFileV2(QString str)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.7.17
* 函数功能: 检查是否为Android日志文件的V2版本
* 输入参数: str:要检查的日志文件的第一行
* 输出参数: 无
* 返回值: 是的返回true,否则返回false
*/
bool MainWindow::checkLogCatFileV2(QString str)
{
reConstruction.clear();
QString ori = str.split(": ").at(0);
if (ori == str) {
return false;
}
QString temp = ori;
while(temp.contains(" ")) {
temp.replace(" ", " ");
}
if (temp.length() < 22) {
return false;
}
if (":" == temp.at(21)) {
temp.remove(21,1);
}
QStringList tempList = temp.split(" ");
if (tempList.size() < 6) {
return false;
}
QString PID = tempList.at(2);
QString TID = tempList.at(3);
temp.remove(21 + PID.length() + 2,TID.length() + 1);
reConstruction.append(temp.append(":"));
reConstruction.append(str.mid(ori.length() + 2));
QStringList list = temp.split(" ");
if ("-" != list.at(0).at(2)) {
reConstruction.clear();
return false;
}
int num = list.at(1).split(":").length();
if (num != 3) {
reConstruction.clear();
return false;
}
temp = list.at(2);
if (!stringIsNum(temp)) {
reConstruction.clear();
return false;
}
if (!QString("VDIWEAF").contains(list.at(3))) {
reConstruction.clear();
return false;
}
return true;
}
/*
* 函数名称: parseLogType(QString str)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.7.17
* 函数功能: 判断日志文件格式类型
* 输入参数: str:要检查的日志文件的第一行
* 输出参数: 无
* 返回值: 是的返回true,否则返回false
*/
void MainWindow::parseLogType(QString str)
{
QString ori = str.split(": ").at(0);
if ((ori == str) || (ori.length() < 22)) {
mLogType = LOG_TYPE_UNKNOWN;
return;
}
QChar temp = ori.at(18);
if (temp == ' ') {
mLogType = LOG_TYPE_1;
} else if ((temp >= '0') && (temp <= '9')) {
mLogType = LOG_TYPE_2;
} else {
mLogType = LOG_TYPE_UNKNOWN;
}
}
/*
* 函数名称: textToList(QString str)
* 函数版本: 1.0.0
* 函数版本: 1.0.1 【2017.4.21】修复部分PID号识别错误的BUG
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 解析日志文件的一行,提取时间、Tag、打印等级和日志内容等信息
* 输入参数: str:日志文件的一行
* 输出参数: 无
* 返回值: 返回解析后提取的信息
*/
QStringList MainWindow::textToList(QStringList str)
{
QString header = str.at(0);
QString content = str.at(1);
QStringList list;
if (mLogType == LOG_TYPE_1) {
list.append(header.mid(0,18)); //时间
list.append((header.at(19) == 'F') ? 'A' : header.at(19));//打印等级
int index = header.indexOf("(");
QString temp = header.mid(index + 1).remove("):");
int length = temp.length();
for (int i = 0; i < length; ++i) {
if (temp.at(length - i - 1) == '(') {
index = index + length - i;
break;
}
}
list.append(header.mid(index + 1).remove("):")); //PID进程号
list.append(header.mid(21,index - 21)); //Tag
list.append(content); //正文内容
} else if (mLogType == LOG_TYPE_2) {
list.append(header.mid(0,21)); //时间
QStringList tempList = header.split(" ");
list.append((tempList.at(3).at(0) == 'F') ? 'A' : tempList.at(3).at(0));//打印等级
int index = header.indexOf("(");
QString temp = header.mid(index + 1).remove("):");
int length = temp.length();
for (int i = 0; i < length; ++i) {
if (temp.at(length - i - 1) == '(') {
index = index + length - i;
break;
}
}
list.append(tempList.at(2)); //PID进程号
temp = tempList.at(4);
if (temp.contains(":")) {
temp.mid(0,temp.length() - 1);
}
list.append(temp); //Tag
list.append(content); //正文内容
}
return list;
}
/*
* 函数名称: addItemToDataList(QString list)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 对日志文件的一行进行解析,并将结果添加到数据表中
* 输入参数: list:日志文件一行解析后的数据结构
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::addItemToDataList(QStringList list)
{
if (list.length() != 5) {
QMessageBox::information(this,"警告","添加项到数据表中出错,原因:解析数据后大小不为5!");
return;
}
mAllTimes.append(list.at(0));
mAllLevels.append(list.at(1));
mAllPIDs.append(list.at(2));
mAllTags.append(list.at(3));
mAllTexts.append(list.at(4));
}
/*
* 函数名称: clearAllDataList()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 初始化变量
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::clearAllDataList()
{
lwFilter->reset();
lwFilter->clear();
lwContent->reset();
lwContent->clear();
QObject::disconnect(ui->cbPID,SIGNAL(currentIndexChanged(int)),this,SLOT(cbPIDChangedSlot()));
while(ui->cbPID->count() != 1) {
ui->cbPID->removeItem(ui->cbPID->count() - 1);
}
QObject::connect(ui->cbPID,SIGNAL(currentIndexChanged(int)),this,SLOT(cbPIDChangedSlot()));
mAllTimes.clear();
mAllLevels.clear();
mAllPIDs.clear();
mAllTags.clear();
mAllTexts.clear();
mAllFilters.clear();
mAllFiltersNums.clear();
mPIDTypes.clear();
mAllLines = 0;
mCurFilters.clear();
mCurFiltersNums.clear();
clearCurDataList();
}
/*
* 函数名称: clearCurDataList()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 清空当前数据表
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::clearCurDataList()
{
mCurTimes.clear();
mCurLevels.clear();
mCurPIDs.clear();
mCurTags.clear();
mCurTexts.clear();
mCurLines = 0;
}
/*
* 函数名称: loadLevelMessage(QString logLevel, QString logTag)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 加载大于等于某一日志等级且指定Tag的所有日志信息
* 输入参数: logLevel:日志等级 logTag:Tag
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::loadLevelMessage(QString logLevel, QString logTag)
{
//用于搜索进程,该处占比40%
int percentMax = 40;
int oldPercent = 0;
int curLevel = getLevelIndex(logLevel);
int length = mAllLines;
int start;
QString curPID = ui->cbPID->currentText();
//如果当前是实时终端模式则采用增量式更新当前数据库;
//如果当前是离线查看模式则清空并重新建立当前数据库;
if (isTerminalMode && !mFilterChangedFlag) {
start = mAllLines - mAddNewLines;
mAddNewLines = 0;
} else {
start = 0;
clearCurDataList(); //先清空当前数据表
}
if (logTag== DEFAULT_TAG) {
for (int i = start; i < length; i++) {
if (getLevelIndex(mAllLevels.at(i)) >= curLevel) {
if ((curPID == mAllPIDs.at(i)) || (curPID == "All")) {
mCurTimes.append(mAllTimes.at(i));
mCurLevels.append(mAllLevels.at(i));
mCurPIDs.append(mAllPIDs.at(i));
mCurTags.append(mAllTags.at(i));
mCurTexts.append(mAllTexts.at(i));
}
}
//如果当前为离线查看模式,且正处于搜索进程中
if (!isTerminalMode && isSearching) {
if (isExitSearch) {
return;
}
int percent = (int)(percentMax * (i + 1) / length);
if (oldPercent != percent) {
setSearchPercentValue(percent);
}
oldPercent = percent;
}
}
} else {
for (int i = start; i < length; i++) {
if (logTag == mAllTags.at(i)) {
if (getLevelIndex(mAllLevels.at(i)) >= curLevel) {
if ((curPID == mAllPIDs.at(i)) || (curPID == "All")) {
mCurTimes.append(mAllTimes.at(i));
mCurLevels.append(mAllLevels.at(i));
mCurPIDs.append(mAllPIDs.at(i));
mCurTags.append(mAllTags.at(i));
mCurTexts.append(mAllTexts.at(i));
}
}
}
//如果当前为离线查看模式,且正处于搜索进程中
if (!isTerminalMode && isSearching) {
if (isExitSearch) {
return;
}
int percent = (int)(percentMax * (i + 1) / length);
if (oldPercent != percent) {
setSearchPercentValue(percent);
}
oldPercent = percent;
}
}
}
mFilterChangedFlag = false;
}
/*
* 函数名称: filterTextHead()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 将日志信息的定位信息头过滤掉(如果含有)
* 输入参数: 无
* 输出参数: 无
* 返回值: 返回去掉定位信息头后的内容
*/
QString MainWindow::filterTextHead(QString text)
{
//定位信息头的格式为:"[ (xxx.java:xxx)#xxx ] "
if (isContainHead(text)) {
QString head = text.split(" ] ")[0] + " ] ";
if (head != text) {
return text.remove(head);
} else {
return text;
}
} else {
return text;
}
}
/*
* 函数名称: isContainHead()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 判断日志信息内容是否含有定位信息头
* 输入参数: 无
* 输出参数: 无
* 返回值: 包含返回true,否则返回false
*/
bool MainWindow::isContainHead(QString text)
{
//定位信息头的格式为:"[ (xxx.java:xxx)#xxx ] "
if (!text.startsWith("[ (")) {
return false;
}
if (text.contains(" ] ")) {
QString tempStr = text.split(" ] ")[0].split("[ ")[1];
if (tempStr.contains(".java:") && tempStr.contains(")#")) {
return true;
} else {
return false;
}
} else {
return false;
}
}
/*
* 函数名称: isContainHead()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 是否建立时间过滤器的信号与槽的连接
* 输入参数: isConnect:是否建立连接
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::isConnectTimeFilter(bool isConnect)
{
if (isConnect) {
QObject::connect(ui->cbStartMonth,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::connect(ui->cbStartDay,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::connect(ui->cbStartHour,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::connect(ui->cbStartMinute,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::connect(ui->cbStartSecond,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::connect(ui->cbStopMonth,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::connect(ui->cbStopDay,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::connect(ui->cbStopHour,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::connect(ui->cbStopMinute,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::connect(ui->cbStopSecond,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
} else {
QObject::disconnect(ui->cbStartMonth,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::disconnect(ui->cbStartDay,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::disconnect(ui->cbStartHour,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::disconnect(ui->cbStartMinute,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::disconnect(ui->cbStartSecond,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::disconnect(ui->cbStopMonth,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::disconnect(ui->cbStopDay,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::disconnect(ui->cbStopHour,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::disconnect(ui->cbStopMinute,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
QObject::disconnect(ui->cbStopSecond,SIGNAL(currentIndexChanged(int)),this,SLOT(timeFilterChangedSlot()));
}
}
/*
* 函数名称: isConnectScroll(bool isConnect)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.10
* 函数功能: 是否建立内容显示区域滚动条的信号与槽的连接
* 输入参数: isConnect:连接或断开
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::isConnectScroll(bool isConnect)
{
if (isConnect) {
QObject::connect(ui->lwContent->verticalScrollBar(),SIGNAL(valueChanged(int)),
this,SLOT(selfVerticalScrollSlot(int)));
QObject::connect(ui->verticalScrollBar,SIGNAL(valueChanged(int)),
this,SLOT(verticalScrollSlot(int)));
QObject::connect(ui->lwContent,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(curContentChangedSlot()));
} else {
QObject::disconnect(ui->lwContent->verticalScrollBar(),SIGNAL(valueChanged(int)),
this,SLOT(selfVerticalScrollSlot(int)));
QObject::disconnect(ui->verticalScrollBar,SIGNAL(valueChanged(int)),
this,SLOT(verticalScrollSlot(int)));
QObject::disconnect(ui->lwContent,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this,SLOT(curContentChangedSlot()));
}
}
/*
* 函数名称: dispCurDataList()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.10
* 函数功能: 显示当前的数据表
* 输入参数: 无
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::dispCurDataList()
{
//计算滚动条的最大值
int max = mCurRange->getTotal() - mCurRange->getPageItemNum() + 1;
//如果该值大于0则显示滚动条,否则隐藏
if (max > 0) {
ui->verticalScrollBar->setHidden(false);
ui->verticalScrollBar->setRange(0,max);
} else {
ui->verticalScrollBar->setHidden(true);
ui->verticalScrollBar->setRange(0,0);
}
autoAdjustTitleLabel(); //自动调节标题标签的位置
dispAreaData(mCurRange,0); //将显示缓冲区的数据显示到屏幕
}
/*
* 函数名称: dispAreaData(ItemsRange *range, int direction)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.10
* 函数功能: 将显示缓冲区中的数据显示到屏幕(所显示的内容由显示缓冲区范围决定)
* 输入参数: range:显示缓冲区范围 direction:滚动条滚动方向
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::dispAreaData(ItemsRange *range, int direction)
{
static bool flag = false;
isConnectScroll(false); //必须先断开滚动条的信号与槽的连接,否则将造成很多不必要的计算,浪费时间
lwContent->clear(); //清空屏幕显示
//获取当前数据表中的数据量,从而确定行号显示栏的位数
int bitNum = QString::number(mCurLines).length();
if (bitNum < 2) {
bitNum = 2;
}
int first = range->getFirst();
int last = range->getLast();
logCurTime("显示范围:" + QString::number(first) + " ,"
+ QString::number(range->getVisibleFirst()) + " ,"
+ QString::number(last));
QString tempText;
QColor color;
//根据缓冲区的范围显示对应的数据
for (int i = first; i <= last; ++i) {
tempText = intToString(i + 1, bitNum) + " "
+ ((isDispTime == true) ? (mCurTimes.at(i) + " ") : "")
+ ((isDispLevel == true) ? (mCurLevels.at(i) + " ") : "")
+ ((isDispPID == true) ? (mCurPIDs.at(i) + " ") : "")
+ ((isDispTag == true) ? (mCurTags.at(i) + " ") : "")
+ ((isDispHead == true) ? (mCurTexts.at(i)) : filterTextHead(mCurTexts.at(i)));
lwContent->addItem(tempText);
color = mColorConfig->at(getLevelIndex(mCurLevels.at(i)));
//将对应日志等级的文本设置成对应的颜色
QListWidgetItem *item = lwContent->item(i - first);
if (item == NULL) {
continue;
}
item->setTextColor(color);
}
if (lwContent->count() > 0) {
//如果是向下滑动,则将焦点设置在最后一行;否则,将焦点设置在第一行
if (direction == 1) {
lwContent->scrollToTop();
lwContent->setCurrentRow(range->getVisibleFirst() + range->getPageItemNum() - 2 - first);
} else {
lwContent->scrollToBottom();
lwContent->setCurrentRow(range->getVisibleFirst() - first);
}
//重新设定滚动条的位置
ui->verticalScrollBar->setValue(range->getVisibleFirst());
}
//获取最新的内部滚动条的值,否则外部滚动条将会发生紊乱
mLastScrollValue = lwContent->verticalScrollBar()->value();
isConnectScroll(true); //重新连接滚动条的信号与槽的连接
curContentChangedSlot();
//如果显示范围是:0,0,-1,且当前应该是有数据的,则立即恢复显示
if ((first == 0) && (range->getVisibleFirst() == 0) && (last == -1)) {
if ((mAllLines > 0) && (flag == false)) {
flag = true;
logCurTime("当前显示范围:0,0,-1,进一步检查是否真的无数据显示...");
// qDebug()<<"【" + QDateTime::currentDateTime().toString("hh:mm:ss.zzz") + "】"
// + "当前显示范围:0,0,-1,进一步检查是否真的无数据显示...";
dispContainSearchString(ui->etSearch->text());
} else {
flag = false;
}
} else {
flag = false;
}
}
/*
* 函数名称: isValidItemsRange(ItemsRange *range)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.10
* 函数功能: 判断是否为一个有效的缓冲区范围
* 输入参数: range:显示缓冲区范围
* 输出参数: 无
* 返回值: 有效返回true,否则返回false
*/
bool MainWindow::isValidItemsRange(ItemsRange *range)
{
return (range->getLast() < mCurLines) && (range->getCount() > 0);
}
/*
* 函数名称: isDirExist(QString fullPath, bool isCreate)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.13
* 函数功能: 判断一个路径是否存在,若不存在,可选择是否创建该路径
* 输入参数: fullPath:路径 isCreate:若不存在,是否创建
* 输出参数: 无
* 返回值: 路径存在返回true,否则返回false
*/
bool MainWindow::isDirExist(QString fullPath, bool isCreate)
{
QString path;
QStringList temp = fullPath.split("/");
if (temp.last().contains(".")) {
path = fullPath.mid(0,fullPath.length() - temp.last().length() - 1);
} else {
path = fullPath;
}
QDir dir(path);
if (dir.exists()) {
return true;
} else if(isCreate) {
return dir.mkpath(path);
} else {
return false;
}
}
/*
* 函数名称: mainThreadWait_ms(int ms)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.15
* 函数功能: 使主线程阻塞一定的时间,目的是为了让所设置的UI界面得到及时的刷新和显示
* 输入参数: ms:要阻塞的毫秒数
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::mainThreadWait_ms(int ms)
{
// eventLoopTimer->start(ms);
// mEventLoop->exec();
QTime time = QTime::currentTime().addMSecs(ms);
while(QTime::currentTime() < time) {
QCoreApplication::processEvents(QEventLoop::AllEvents,100);
}
}
/*
* 函数名称: addHistoryAction(QString path)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.16
* 函数功能: 添加打开文件历史记录
* 输入参数: path:文件的绝对路径
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::addHistoryAction(QString path)
{
QList<QAction*> list = ui->history->actions();
QMenu *history = ui->history;
int size = list.size();
//清空当前的所有Action,后面重新添加
for (int i = 0; i < size; ++i) {
history->removeAction(list.at(i));
}
//如果数量大于1,且倒数第二个为分隔符
if ((size > 1) && (list.at(size - 2)->text().isEmpty())) {
//如果数量大于等于了最大数量,则删除最旧的一个
if ((MAX_SAVE_HISTORY_NUM > 0) && (size >= (2 + MAX_SAVE_HISTORY_NUM))) {
list.removeAt(size - 3);
size--;
}
}
//添加最新的
history->addAction(path);
//添加之前的
QString text = "";
for (int i = 0; i < (size - 1); ++i) {
text = list.at(i)->text();
//如果不是分隔符,且不是当前打开的文件
if (!text.isEmpty() && (text != path)) {
history->addAction(text);
}
}
//添加分隔符,之前的分隔符已经被去掉了
history->addSeparator();
//添加最后一个(即清空历史记录)
history->addAction(list.at(size - 1)->text());
mHistory.clear();
list = history->actions();
size = list.size() - 2;
for (int i = 0; i < size; ++i) {
text = list.at(i)->text();
//logCurTime("history[" + QString::number(i) + "]=" + text);
mHistory.append(text);
}
updateHistoryAction(mHistory);
history->setEnabled(true); //使能该选项(因为已经有历史记录存在了)
}
/*
* 函数名称: updateHistoryAction(QStringList history)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.3.17
* 函数功能: 更新文件打开的历史记录
* 输入参数: history:历史记录
* 输出参数: 无
* 返回值: 无
*/
void MainWindow::updateHistoryAction(QStringList history)
{
QList<QAction*> list = ui->history->actions();
QMenu *action = ui->history;
int size = list.size();
//清空当前的所有Action,后面重新添加
for (int i = 0; i < size; ++i) {
action->removeAction(list.at(i));
}
size = history.size();
for (int i = 0; i < size; ++i) {
action->addAction(history.at(i));
}
//添加分隔符
action->addSeparator();
//添加最后一个(即清空历史记录)
action->addAction("清空历史记录");
//将新的设置更新到设置文件中
bool isSaveSuccess = mSettingParse->saveHistoryToFile(mSettingFilePath,mHistory);
if (isSaveSuccess) {
logCurTime("保存历史记录成功!");
} else {
logCurTime("保存历史记录失败!");
}
}
/*
* 函数名称: isContainString(QString str, QString containStr)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 判断在一个字符串中是否包含某一字符串
* 输入参数: str:要判断的字符串 containStr:是否包含的字符串
* 输出参数: 无
* 返回值: 包含返回true,否则返回false
*/
bool MainWindow::isContainString(QString str, QString containStr)
{
return str.contains(containStr,Qt::CaseInsensitive);
}
/*
* 函数名称: isContainTime()
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.9
* 函数功能: 判断一个时间是否属于起止时间范围内
* 输入参数: 无
* 输出参数: 无
* 返回值: 属于返回true,否则返回false
*/
bool MainWindow::isContainTime(QString time)
{
int result1 = QString::compare(time, mStartTime);
int result2 = QString::compare(time, mStopTime);
return (result1 >= 0) && (result2 <= 0);
}
/*
* 函数名称: getLevelIndex(QString logLevel)
* 函数版本: 1.0.0
* 作者: HXL
* 创建日期: 2017.2.4
* 函数功能: 根据日志等级获取等级的索引值
* 输入参数: logLevel:日志等级
* 输出参数: 无
* 返回值: 等级的索引值
*/
int MainWindow::getLevelIndex(QString logLevel)
{
int levelIndex = 0;
if ((logLevel == "V") || (logLevel == "verbose")) {
levelIndex = 0;
} else if (logLevel == "D" || (logLevel == "debug")) {
levelIndex = 1;
} else if (logLevel == "I" || (logLevel == "info")) {
levelIndex = 2;
} else if (logLevel == "W" || (logLevel == "warn")) {
levelIndex = 3;
} else if (logLevel == "E" || (logLevel == "error")) {
levelIndex = 4;
} else if (logLevel == "A" || (logLevel == "assert") || (logLevel == "F")) {
levelIndex = 5;
}
return levelIndex;
}
C++
1
https://gitee.com/surface-pro/androidrizhifenxigongju.git
git@gitee.com:surface-pro/androidrizhifenxigongju.git
surface-pro
androidrizhifenxigongju
Android日志分析工具
master

搜索帮助