void DirWidget::startSync(const QString &file){ //Update date_format based on user settings if(file == sessionsettings_config_file){ setDateFormat(); } else if(file == snapbasedir){ emit findSnaps(ID, normalbasedir); } //snapshot list changed else if(file == normalbasedir){ if(synctimer->isActive()){ synctimer->stop(); } //already starting a sync - restart the timer synctimer->start(); }else{ //Some file in the directory got changed - start the time for a dir reload // -- This prevents a directory from refreshing constantly if a file within the directory is changing all the time (such as a log file) if(!synctimer->isActive()){ synctimer->start(); } } }
void DirWidget::on_slider_snap_valueChanged(int val){ //Update the snapshot interface ui->tool_snap_newer->setEnabled(val < ui->slider_snap->maximum()); ui->tool_snap_older->setEnabled(val > ui->slider_snap->minimum()); if(val >= snapshots.length() || val < 0){ ui->label_snap->setText(tr("Current")); }else if(QFile::exists(snapbasedir+snapshots[val])){ ui->label_snap->setText( QFileInfo(snapbasedir+snapshots[val]).lastModified().toString(Qt::DefaultLocaleShortDate) ); } //Exit if a non-interactive snapshot change if(!ui->group_snaps->isEnabled()){ return; } //internal change - do not try to change the actual info //Determine which snapshot is now selected QString dir; if(DEBUG){ qDebug() << "Changing snapshot:" << CDIR << val << snapbasedir; } stopload = true; //stop any currently-loading procedures if(val >= snapshots.length() || val < 0){ //active system selected if(DEBUG){ qDebug() << " - Load Active system:" << normalbasedir; } dir = normalbasedir; }else{ dir = snapbasedir+snapshots[val]+"/"; if(!QFile::exists(dir)){ //This snapshot must have been removed in the background by pruning tools // move to a newer snapshot or the current base dir as necessary qDebug() << "Snapshot no longer available:" << dir; qDebug() << " - Reloading available snapshots"; emit findSnaps(ID, normalbasedir); return; } //if(snaprelpath.isEmpty()){ //Need to figure out the relative path within the snapshot snaprelpath = normalbasedir.section(snapbasedir.section(ZSNAPDIR,0,0), 1,1000); if(DEBUG){ qDebug() << " - new snapshot-relative path:" << snaprelpath; } //} dir.append(snaprelpath); dir.replace("//","/"); //just in case any duplicate slashes from all the split/combining if(DEBUG){ qDebug() << " - Load Snapshot:" << dir; } } //Make sure this directory exists, and back up as necessary /*while(!QFile::exists(dir) && !dir.isEmpty()){ dir = dir.section("/",0,-2); //back up one dir }*/ if(dir.isEmpty()){ return; } //Load the newly selected snapshot stopload = true; //just in case it is still loading emit LoadDirectory(ID, dir); }
void MainUI::OpenDirs(QStringList dirs){ //Now open the dirs if(dirs.isEmpty()){ dirs << QDir::homePath(); } QStringList invalid; for(int i=0; i<dirs.length(); i++){ if(dirs[i].simplified().isEmpty()){ continue; } //Open this directory in a viewer if(dirs[i].endsWith("/")){ dirs[i].chop(1); } if(!QFile::exists(dirs[i])){ invalid << dirs[i]; continue; } if(DEBUG){ qDebug() << "Open Directory:" << dirs[i]; } ///Get a new Unique ID int id = 0; for(int j=0; j<DWLIST.length(); j++){ if(DWLIST[j]->id().section("-",1,1).toInt() >= id){ id = DWLIST[j]->id().section("-",1,1).toInt()+1; } } //Create the new DirWidget DirWidget *DW = new DirWidget("DW-"+QString::number(id), this); DW->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); ui->BrowserLayout->addWidget(DW); DWLIST << DW; //Connect the signals/slots for it connect(DW, SIGNAL(OpenDirectories(QStringList)), this, SLOT(OpenDirs(QStringList)) ); connect(DW, SIGNAL(LoadDirectory(QString, QString)), worker, SLOT(GetDirData(QString, QString)) ); connect(DW, SIGNAL(findSnaps(QString, QString)), worker, SLOT(GetSnapshotData(QString, QString)) ); connect(DW, SIGNAL(PlayFiles(LFileInfoList)), this, SLOT(OpenPlayer(LFileInfoList)) ); connect(DW, SIGNAL(ViewFiles(LFileInfoList)), this, SLOT(OpenImages(LFileInfoList)) ); connect(DW, SIGNAL(LaunchTerminal(QString)), this, SLOT(OpenTerminal(QString)) ); connect(DW, SIGNAL(CutFiles(QStringList)), this, SLOT(CutFiles(QStringList)) ); connect(DW, SIGNAL(CopyFiles(QStringList)), this, SLOT(CopyFiles(QStringList)) ); connect(DW, SIGNAL(FavoriteFiles(QStringList)), this, SLOT(FavoriteFiles(QStringList)) ); connect(DW, SIGNAL(RenameFiles(QStringList)), this, SLOT(RenameFiles(QStringList)) ); connect(DW, SIGNAL(RemoveFiles(QStringList)), this, SLOT(RemoveFiles(QStringList)) ); connect(DW, SIGNAL(PasteFiles(QString,QStringList)), this, SLOT(PasteFiles(QString, QStringList)) ); connect(DW, SIGNAL(CloseBrowser(QString)), this, SLOT(CloseBrowser(QString)) ); //Now create the tab for this if(radio_view_tabs->isChecked()){ int index = tabBar->addTab( LXDG::findIcon("folder-open",""), dirs[i].section("/",-1) ); tabBar->setTabWhatsThis( index, "DW-"+QString::number(id) ); tabBar->setCurrentIndex(index); }else{ //Just make sure the browser tab is visible bool found = false; for(int i=0; i<tabBar->count() && !found; i++){ if(tabBar->tabWhatsThis(i)=="browser"){ tabBar->setCurrentIndex(i); found=true; } } if(!found){ //Need to create the generic Browser tab int index = tabBar->addTab( LXDG::findIcon("folder-open",""), "Browser" ); tabBar->setTabWhatsThis( index, "browser" ); tabBar->setCurrentIndex(index); } } //Initialize the widget with the proper settings DW->setShowDetails(radio_view_details->isChecked()); DW->setShowSidebar(ui->actionShow_Action_Buttons->isChecked()); QList<DirWidget::DETAILTYPES> details; details <<DirWidget::NAME << DirWidget::SIZE << DirWidget::TYPE << DirWidget::DATEMOD; DW->setDetails(details); //Which details to show and in which order (L->R) DW->setShowThumbnails(ui->actionShow_Thumbnails->isChecked()); DW->setThumbnailSize(settings->value("iconsize", 32).toInt()); DW->setDirCompleter(dirCompleter); DW->setShowCloseButton(!radio_view_tabs->isChecked()); //Now load the directory DW->ChangeDir(dirs[i]); //kick off loading the directory info } //Update visibilities tabChanged(tabBar->currentIndex()); tabBar->setVisible( tabBar->count() > 1 ); if(!invalid.isEmpty()){ QMessageBox::warning(this, tr("Invalid Directories"), tr("The following directories are invalid and could not be opened:")+"\n"+invalid.join(", ") ); } //Double check that there is at least 1 dir loaded //qDebug() << "OpenDirs:" << DWLIST.length() << dirs << invalid << tabBar->currentIndex(); if(DWLIST.isEmpty()){ OpenDirs(QStringList()); } }
// ================ // PUBLIC SLOTS // ================ void DirWidget::LoadDir(QString dir, QList<LFileInfo> list){ if(dir.isEmpty()){ return; } //nothing to do QTime time; if(DEBUG){time.start(); } qDebug() << "Load Dir:" << dir; QString lastdir = CDIR; //for some checks later QString lastbasedir = normalbasedir; CDIR = dir; if(CDIR.endsWith("/") && CDIR.length() > 1){ CDIR.chop(1); } CLIST = list; //save for later canmodify = QFileInfo(CDIR).isWritable(); if(DEBUG){ qDebug() << "Clear UI:" <<time.elapsed(); } //Clear the status text if(!canmodify){ui->label_status->setText(tr("(Limited Access) ")); } else{ ui->label_status->setText(""); } //Hide the extra buttons for a moment ui->tool_goToPlayer->setVisible(false); ui->tool_goToImages->setVisible(false); ui->tool_new_dir->setVisible(canmodify); ui->tool_new_file->setVisible(canmodify); //Set the drag/drop info as appripriate if(canmodify){ listWidget->setWhatsThis(CDIR); treeWidget->setWhatsThis(CDIR); }else{ listWidget->setWhatsThis(""); treeWidget->setWhatsThis(""); } bool updateThumbs = (lastdir != CDIR); //Determine if this is an internal ZFS snapshot bool loadsnaps = false; if(DEBUG){ qDebug() << "Load Snap Info:" << time.elapsed(); } if( dir.contains(ZSNAPDIR) ){ //This is a zfs snapshot - only update the saved paths necessary to rotate between snapshots/system snaprelpath = dir.section(ZSNAPDIR,1,1000).section("/",1,1000); //the relative path inside the snapshot if(snaprelpath.endsWith("/")){ snaprelpath.chop(1); } normalbasedir = dir.section(ZSNAPDIR,0,0)+"/"+snaprelpath; //Update the new base directory if(normalbasedir.endsWith("/")){ normalbasedir.chop(1); } line_dir->setText(normalbasedir); //See if this was a manual move to the directory, or an internal move QString tmp = dir.section(ZSNAPDIR,0,0); if(tmp != snapbasedir.section(ZSNAPDIR,0,0)){ loadsnaps = true; //different snapshot loaded - need to update internally } }else{ //This is a normal directory - prompt for snapshot information line_dir->setText(CDIR); normalbasedir = CDIR; if(!snapbasedir.isEmpty()){ watcher->removePath(snapbasedir); } snapbasedir.clear(); loadsnaps = true; } if(loadsnaps){ //kick this off while still loading the dir contents ui->group_snaps->setEnabled(false); //to prevent the snap updates to be automatically used ui->group_snaps->setVisible(false); ui->slider_snap->setRange(1,1); emit findSnaps(ID, normalbasedir); } if(DEBUG){ qDebug() << "Update History:" <<time.elapsed(); } //Now update the history for this browser //qDebug() << "History:" << history << normalbasedir << lastbasedir; if(!history.isEmpty() && history.last() == normalbasedir && lastbasedir!=normalbasedir ){ //We went back one - remove this from the history history.takeLast(); ui->actionBack->setEnabled(!history.isEmpty()); //qDebug() << " - Duplicate: removed item"; }else if(lastbasedir!=normalbasedir){ //not a refresh or internal snapshot change //qDebug() << " - New History Item:" << normalbasedir; history << normalbasedir; ui->actionBack->setEnabled(history.length()>1); } if(DEBUG){ qDebug() << "Update Watcher:" << time.elapsed(); } //Clear the current watcher if(!watcher->directories().isEmpty()){ watcher->removePaths(watcher->directories()); } if(!watcher->files().isEmpty()){ watcher->removePaths(watcher->files()); } watcher->addPath(CDIR); // add sessionsettings to watcher so date_format can be update based on user settings watcher->addPath(sessionsettings_config_file); ui->actionStopLoad->setVisible(true); stopload = false; //Clear the display widget (if a new directory) if(DEBUG){ qDebug() << "Clear Browser Widget:" << time.elapsed(); } double scrollpercent = -1; if(updateThumbs){ needThumbs.clear(); } if(lastbasedir != normalbasedir){ if(showDetails){ treeWidget->clear(); } else{ listWidget->clear(); } QApplication::processEvents(); //make sure it is cleared right away }else{ //Need to be smarter about which items need to be removed // - compare the old/new lists and remove any items not in the new listing (new items taken care of below) QStringList newfiles; //just the filenames for(int i=0; i<CLIST.length(); i++){ newfiles << CLIST[i].fileName(); } if(showDetails){ for(int i=0; i<treeWidget->topLevelItemCount(); i++){ if( !newfiles.contains(treeWidget->topLevelItem(i)->whatsThis(0).section("/",-1)) ){ if(!updateThumbs){ needThumbs.removeAll( treeWidget->topLevelItem(i)->whatsThis(0).section("::::",1,50)); } delete treeWidget->takeTopLevelItem(i); i--; } } QApplication::processEvents(); //make sure the scrollbar is up to date after removals scrollpercent = treeWidget->verticalScrollBar()->value()/( (double) treeWidget->verticalScrollBar()->maximum()); }else{ for(int i=0; i<listWidget->count(); i++){ if( !newfiles.contains(listWidget->item(i)->text()) ){ if(!updateThumbs){ needThumbs.removeAll( listWidget->item(i)->whatsThis().section("::::",1,50)); } delete listWidget->takeItem(i); i--; } } QApplication::processEvents(); //make sure the scrollbar is up to date after removals scrollpercent = listWidget->horizontalScrollBar()->value()/( (double) listWidget->horizontalScrollBar()->maximum()); } } //end check for CDIR reload //Now fill the display widget bool hasimages, hasmultimedia; hasimages = hasmultimedia = false; int numdirs = 0; qint64 filebytes = 0; //Setup the timer to see when we should process events /*QTimer updatetime; updatetime.setInterval(1000); //1 second updates updatetime.setSingleShot(true); updatetime.start();*/ QTime updatetime = QTime::currentTime().addMSecs(500); if(DEBUG){ qDebug() << "Start Loop over items:" << time.elapsed(); } for(int i=0; i<list.length(); i++){ if(stopload){ ui->actionStopLoad->setVisible(false); return; } //stop right now if(!hasimages && list[i].isImage()){ hasimages = true; ui->tool_goToImages->setVisible(true); } else if(!hasmultimedia && list[i].isAVFile()){ hasmultimedia = true; ui->tool_goToPlayer->setVisible(true); } //Update statistics if(list[i].isDir()){ numdirs++; } else{ filebytes += list[i].size(); } watcher->addPath(list[i].absoluteFilePath()); if(showDetails){ //Now create all the individual items for the details tree CQTreeWidgetItem *it; bool addnew = false; //See if an item already exists for this file QList<QTreeWidgetItem*> items = treeWidget->findItems(list[i].fileName(),Qt::MatchExactly,0); //NOTE: This requires column 0 to be the name if(items.isEmpty()){ it = new CQTreeWidgetItem(); addnew = true; }else{ // Safe downcasting because CQTreeWidgetItem only redefines the virtual function bool opearot<. Not new methos added. it = static_cast<CQTreeWidgetItem *> (items.first()); } //Now update the entry contents it->setWhatsThis(0, QString(canmodify ? "cut": "copy")+"::::"+list[i].absoluteFilePath()); for(int t=0; t<listDetails.length(); t++){ switch(listDetails[t]){ case NAME: it->setText(t,list[i].fileName()); it->setStatusTip(t, list[i].fileName()); //Since the icon/image is based on the filename - only update this for a new item // (This is the slowest part of the routine) if(list[i].isImage()&& (addnew || updateThumbs)){ if(showThumbs){ it->setIcon(t, LXDG::findIcon("fileview-preview","image-x-generic") ); needThumbs << list[i].fileName(); }else{ it->setIcon(t, LXDG::findIcon(list[i].iconfile(),"image-x-generic") ); } }else if(addnew){ it->setIcon(t, LXDG::findIcon(list[i].iconfile(),"unknown") ); } break; case SIZE: if(!list[i].isDir()){ it->setText(t, LUtils::BytesToDisplaySize(list[i].size()) ); } break; case TYPE: it->setText(t, list[i].mimetype()); break; case DATEMOD: { QStringList datetime_format = getDateFormat(); // Save datetime in WhatThis value. Lately will be used by CQTreeWidgetItem for sorting by date it->setWhatsThis(t, list[i].lastModified().toString("yyyyMMddhhmmsszzz")); // Default configurition. Fallback to Qt::DefaultLocaleShortDate for formats if(datetime_format.at(0).isEmpty() && datetime_format.at(1).isEmpty()) it->setText(t, list[i].lastModified().toString(Qt::DefaultLocaleShortDate) ); // Date is setted but time not. Time goes to default else if(!datetime_format.at(0).isEmpty() && datetime_format.at(1).isEmpty()) it->setText(t, list[i].lastModified().date().toString(datetime_format.at(0)) + " " + list[i].lastModified().time().toString(Qt::DefaultLocaleShortDate)); // Time is setted but date not. Date goes to default else if(datetime_format.at(0).isEmpty() && !datetime_format.at(1).isEmpty()) it->setText(t, list[i].lastModified().date().toString(Qt::DefaultLocaleShortDate) + " " + list[i].lastModified().time().toString(datetime_format.at(1))); // Both time and date setted. else it->setText(t, list[i].lastModified().date().toString(datetime_format.at(0)) + " " + list[i].lastModified().time().toString(datetime_format.at(1))); break; } case DATECREATE: { QStringList datetime_format = getDateFormat(); it->setWhatsThis(DATECREATE, list[i].lastModified().toString("yyyyMMddhhmmsszzz")); if(datetime_format.at(0).isEmpty() && datetime_format.at(1).isEmpty()) it->setText(t, list[i].lastModified().toString(Qt::DefaultLocaleShortDate) ); else if(!datetime_format.at(0).isEmpty() && datetime_format.at(1).isEmpty()) it->setText(t, list[i].lastModified().date().toString(datetime_format.at(0)) + " " + list[i].lastModified().time().toString(Qt::DefaultLocaleShortDate)); else if(datetime_format.at(0).isEmpty() && !datetime_format.at(1).isEmpty()) it->setText(t, list[i].lastModified().date().toString(Qt::DefaultLocaleShortDate) + " " + list[i].lastModified().time().toString(datetime_format.at(1))); else it->setText(t, list[i].lastModified().date().toString(datetime_format.at(0)) + " " + list[i].lastModified().time().toString(datetime_format.at(1))); break; } } } if(addnew){ treeWidget->addTopLevelItem(it); } if(tmpSel.contains(list[i].absoluteFilePath())){ it->setSelected(true); } if(lastdir == CDIR+"/"+list[i].fileName()){ treeWidget->setCurrentItem(it); treeWidget->scrollToItem(it); } }else{ //Create all the individual items for the basic list QListWidgetItem *it; //See if there is an existing item to re-use bool addnew = false; QList<QListWidgetItem*> items = listWidget->findItems(list[i].fileName(), Qt::MatchExactly); if(items.isEmpty()){ it = new QListWidgetItem(); addnew = true; }else{ it = items.first(); } it->setWhatsThis( QString(canmodify ? "cut": "copy")+"::::"+list[i].absoluteFilePath()); //used for drag and drop it->setText(list[i].fileName()); it->setStatusTip(list[i].fileName()); //Since the icon/image is based on the filename - only update this for a new items (non-thumbnail) // (This is the slowest part of the routine) if(list[i].isImage() && (addnew || updateThumbs) ){ if(showThumbs){ it->setIcon(LXDG::findIcon("fileview-preview","image-x-generic") ); needThumbs << list[i].fileName(); }else{ it->setIcon(LXDG::findIcon(list[i].iconfile(),"image-x-generic") ); } }else if(addnew){ it->setIcon(LXDG::findIcon(list[i].iconfile(),"unknown") ); } listWidget->addItem(it); if(tmpSel.contains(list[i].absoluteFilePath())){ it->setSelected(true); } if(lastdir == CDIR+"/"+list[i].fileName()){ listWidget->setCurrentItem(it); listWidget->scrollToItem(it); } } if(QTime::currentTime() > updatetime){ QApplication::processEvents(); updatetime = QTime::currentTime().addMSecs(500); }//keep the UI snappy while loading a directory if(DEBUG){ qDebug() << " - item finished:" << i << time.elapsed(); } } tmpSel.clear(); if(DEBUG){ qDebug() << "Done with item loop:" << time.elapsed() << list.length(); } ui->actionStopLoad->setVisible(false); //Another check to ensure the current item is visible (or return to the same scroll position) if(stopload){ return; } //stop right now if(scrollpercent<0){ if(showDetails){ for(int t=0; t<treeWidget->columnCount(); t++){treeWidget->resizeColumnToContents(t); } if(treeWidget->currentItem()!=0){ treeWidget->scrollToItem(treeWidget->currentItem()); } }else{ if(listWidget->currentItem()!=0){ listWidget->scrollToItem(listWidget->currentItem()); } } }else{ if(showDetails){ treeWidget->verticalScrollBar()->setValue( qRound(treeWidget->verticalScrollBar()->maximum()*scrollpercent) ); }else{ listWidget->horizontalScrollBar()->setValue( qRound(listWidget->horizontalScrollBar()->maximum()*scrollpercent) ); } } if(stopload){ return; } //stop right now if(DEBUG){ qDebug() << "Assemble Status Message:" << time.elapsed(); } //Assemble any status message QString stats = QString(tr("Capacity: %1")).arg(LOS::FileSystemCapacity(CDIR)); if(list.length()>0){ stats.prepend("\t"); if(numdirs < list.length()){ //Has Files stats.prepend( QString(tr("Files: %1 (%2)")).arg(QString::number(list.length()-numdirs), LUtils::BytesToDisplaySize(filebytes)) ); } if(numdirs > 0){ //Has Dirs if(numdirs<list.length()){ stats.prepend(" / "); }//has files output already stats.prepend( QString(tr("Dirs: %1")).arg(QString::number(numdirs)) ); } } if(stopload){ return; } //stop right now if(!canmodify){ stats.prepend(tr("(Limited Access) ")); } ui->label_status->setText( stats.simplified() ); if(DEBUG){ qDebug() << "DONE:" << time.elapsed(); } if(showThumbs){ thumbThread = QtConcurrent::run(this, &DirWidget::startLoadThumbs); } }