/***************************************************************************************** * Add a FileInfo to the parent node to the proper position. * tree_path is the tree path of the parent node. * ****************************************************************************************/ GList *fm_dir_tree_model_insert_file_info (FmDirTreeModel *dir_tree_model, GList *parent_node, GtkTreePath *tree_path, FmFileInfo *file_info) { FmDirTreeItem *parent_item = (FmDirTreeItem*) parent_node->data; FmDirTreeItem *dir_tree_item = fm_dir_tree_item_new (dir_tree_model, parent_node, file_info); // Don't show hidden files... if (!dir_tree_model->show_hidden && file_info->path->name[0] == '.') { parent_item->hidden_children = g_list_prepend (parent_item->hidden_children, dir_tree_item); return parent_item->hidden_children; } // Don't show links... if (!dir_tree_model->show_symlinks && fm_file_info_is_symlink (file_info)) { parent_item->hidden_children = g_list_prepend (parent_item->hidden_children, dir_tree_item); return parent_item->hidden_children; } GList *item_list = fm_dir_tree_model_insert_sorted (dir_tree_model, parent_node, tree_path, dir_tree_item); char *tmp_path = gtk_tree_path_to_string (tree_path); TREEVIEW_DEBUG ("TREEVIEW_DEBUG: fm_dir_tree_model_insert_file_info: file = %s\t index = %d\n\n", fm_file_info_get_name (file_info), file_info->sorting_index); g_free (tmp_path); return item_list; }
static void fm_dir_tree_model_add_place_holder_child_item (FmDirTreeModel *dir_tree_model, GList *parent_node, GtkTreePath *tree_path, gboolean emit_signal) { FmDirTreeItem *parent_item = (FmDirTreeItem*) parent_node->data; // Check if the parent node can expand... FmFileInfo *file_info = parent_item->file_info; FmPath *path = fm_file_info_get_path (file_info); TREEVIEW_DEBUG ("TREEVIEW_DEBUG: fm_dir_tree_model_add_place_holder_child_item: file = %s\t emit_signal = %d\n", fm_file_info_get_name (file_info), emit_signal); // don't expand the trash can... // TODO_axl: add a can_expand flag into the file_info if (fm_path_is_trash (path) && fm_path_is_root (path)) return; TREEVIEW_DEBUG ("TREEVIEW_DEBUG: fm_dir_tree_model_add_place_holder_child_item: create place holder\n\n"); FmDirTreeItem *dir_tree_item = fm_dir_tree_item_new (dir_tree_model, parent_node, NULL); parent_item->children = g_list_prepend (parent_item->children, dir_tree_item); if (!emit_signal) return; GtkTreeIter it; fm_dir_tree_model_item_to_tree_iter (dir_tree_model, parent_item->children, &it); gtk_tree_path_append_index (tree_path, 0); gtk_tree_model_row_inserted (GTK_TREE_MODEL (dir_tree_model), tree_path, &it); gtk_tree_path_up (tree_path); }
void DesktopWindow::onIndexesMoved(const QModelIndexList& indexes) { // remember the custom position for the items Q_FOREACH(const QModelIndex& index, indexes) { // Under some circumstances, Qt might emit indexMoved for // every single cells in the same row. (when QAbstractItemView::SelectItems is set) // So indexes list may contain several indixes for the same row. // Since we only care about rows, not individual cells, // let's handle column 0 of every row here. if(index.column() == 0) { FmFileInfo* file = proxyModel_->fileInfoFromIndex(index); QRect itemRect = listView_->rectForIndex(index); QPoint tl = itemRect.topLeft(); QRect workArea = qApp->desktop()->availableGeometry(screenNum_); workArea.adjust(12, 12, -12, -12); if(customItemPos_.keys(tl).isEmpty() // don't put items on each other && tl.x() >= workArea.x() && tl.y() >= workArea.y() && tl.x() + listView_->gridSize().width() <= workArea.right() + 1 // for historical reasons (-> Qt doc) && tl.y() + listView_->gridSize().height() <= workArea.bottom() + 1) { // as above QByteArray name = fm_file_info_get_name(file); customItemPos_[name] = tl; // qDebug() << "indexMoved:" << name << index << itemRect; } } } saveItemPositions(); queueRelayout(); }
bool ProxyFilter::filterAcceptsRow(const Fm::ProxyFolderModel* model, FmFileInfo* info) const { if(!model || !info) return true; QString baseName(fm_file_info_get_name(info)); if(!virtHiddenList_.isEmpty() && !model->showHidden() && virtHiddenList_.contains(baseName)) return false; if(!filterStr_.isEmpty() && !baseName.contains(filterStr_, Qt::CaseInsensitive)) return false; return true; }
void DesktopWindow::prepareFileMenu(Fm::FileMenu* menu) { // qDebug("DesktopWindow::prepareFileMenu"); PCManFM::View::prepareFileMenu(menu); QAction* action = new QAction(tr("Stic&k to Current Position"), menu); action->setCheckable(true); menu->insertSeparator(menu->separator2()); menu->insertAction(menu->separator2(), action); FmFileInfoList* files = menu->files(); // select exactly one item if(fm_file_info_list_get_length(files) == 1) { FmFileInfo* file = menu->firstFile(); if(customItemPos_.find(fm_file_info_get_name(file)) != customItemPos_.end()) { // the file item has a custom position action->setChecked(true); } } connect(action, &QAction::toggled, this, &DesktopWindow::onStickToCurrentPos); }
void DesktopWindow::onStickToCurrentPos(bool toggled) { QAction* action = static_cast<QAction*>(sender()); Fm::FileMenu* menu = static_cast<Fm::FileMenu*>(action->parent()); QModelIndexList indexes = listView_->selectionModel()->selectedIndexes(); if(!indexes.isEmpty()) { FmFileInfo* file = menu->firstFile(); QByteArray name = fm_file_info_get_name(file); QModelIndex index = indexes.first(); if(toggled) { // remember to current custom position QRect itemRect = listView_->rectForIndex(index); customItemPos_[name] = itemRect.topLeft(); saveItemPositions(); } else { // cancel custom position and perform relayout QHash<QByteArray, QPoint>::iterator it = customItemPos_.find(name); if(it != customItemPos_.end()) { customItemPos_.erase(it); saveItemPositions(); relayoutItems(); } } } }
static gboolean subdir_check_job (GIOSchedulerJob *job, GCancellable *cancellable, gpointer user_data) { FmDirTreeModel *dir_tree_model = FM_DIR_TREE_MODEL (user_data); // Lock ---------------------------------------------------------------------------------------- g_mutex_lock (dir_tree_model->subdir_checks_mutex); GList *item_list = (GList*) g_queue_pop_head (&dir_tree_model->subdir_checks); FmDirTreeItem *dir_tree_item = (FmDirTreeItem*) item_list->data; dir_tree_model->current_subdir_check = item_list; // If the directory is a Drive, get it's target directory... //gboolean is_drive = fm_file_info_is_drive (dir_tree_item->file_info); GFile *gfile; gboolean is_mountable = fm_file_info_is_mountable (dir_tree_item->file_info); if (is_mountable) { gfile = g_file_new_for_path (fm_file_info_get_target (dir_tree_item->file_info)); } else { gfile = fm_path_to_gfile (fm_file_info_get_path (dir_tree_item->file_info)); } g_mutex_unlock (dir_tree_model->subdir_checks_mutex); // Unlock -------------------------------------------------------------------------------------- //~ GError *gerror = NULL; //~ gfile_info = g_file_query_info (gfile, gfile_info_query_attribs, 0, fm_job_get_cancellable (fmjob), &gerror); /** * Parse input directory... * */ char *directory = fm_file_info_get_name (dir_tree_item->file_info); JOB_DEBUG ("\n----------------------------------------------------------------------------------------------\n"); JOB_DEBUG ("JOB_DEBUG: subdir_check_job: check \"%s\"\n", directory); JOB_DEBUG ("----------------------------------------------------------------------------------------------\n"); if (is_mountable) { JOB_DEBUG ("JOB_DEBUG: subdir_check_job: %s is mountable type !!!\n\n", directory); } GFileEnumerator *enumerator = g_file_enumerate_children (gfile, G_FILE_ATTRIBUTE_STANDARD_NAME"," G_FILE_ATTRIBUTE_STANDARD_TYPE"," G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN, 0, cancellable, NULL); gboolean has_subdir = FALSE; if (enumerator) { while (!g_cancellable_is_cancelled (cancellable)) { GFileInfo *gfile_info = g_file_enumerator_next_file (enumerator, cancellable, NULL); if (G_LIKELY (gfile_info)) { GFileType g_file_type = g_file_info_get_file_type (gfile_info); gboolean is_hidden = g_file_info_get_is_hidden (gfile_info); //~ TREEVIEW_DEBUG ("TREEVIEW_DEBUG: subdir_check_job: GFileInfo for %s = %d\n", //~ g_file_info_get_name (gfile_info), g_file_type); g_object_unref (gfile_info); if (g_file_type == G_FILE_TYPE_DIRECTORY || g_file_type == G_FILE_TYPE_MOUNTABLE) { if (dir_tree_model->show_hidden || !is_hidden) { JOB_DEBUG ("JOB_DEBUG: subdir_check_job: A directory found in \"%s\" !!!\n\n", directory); has_subdir = TRUE; break; } } } else { break; } } GError *error = NULL; g_file_enumerator_close (enumerator, cancellable, &error); g_object_unref (enumerator); } else { JOB_DEBUG ("JOB_DEBUG: subdir_check_job: Error: can't read \"%s\"...\n", directory); } // NO_DEBUG ("check result - %s has_dir: %d\n", g_file_get_parse_name (gfile), has_subdir); g_object_unref (gfile); if (!has_subdir) { JOB_DEBUG ("JOB_DEBUG: subdir_check_job: No directory found in \"%s\"\n\t\t\t > Remove place holder\n\n", directory); return g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc) subdir_check_remove_place_holder, dir_tree_model, NULL); } return subdir_check_finish (dir_tree_model); }
// QListView does item layout in a very inflexible way, so let's do our custom layout again. // FIXME: this is very inefficient, but due to the design flaw of QListView, this is currently the only workaround. void DesktopWindow::relayoutItems() { loadItemPositions(); // something may have changed // qDebug("relayoutItems()"); if(relayoutTimer_) { // this slot might be called from the timer, so we cannot delete it directly here. relayoutTimer_->deleteLater(); relayoutTimer_ = NULL; } QDesktopWidget* desktop = qApp->desktop(); int screen = 0; int row = 0; int rowCount = proxyModel_->rowCount(); for(;;) { if(desktop->isVirtualDesktop()) { if(screen >= desktop->numScreens()) break; }else { screen = screenNum_; } QRect workArea = desktop->availableGeometry(screen); workArea.adjust(12, 12, -12, -12); // add a 12 pixel margin to the work area // qDebug() << "workArea" << screen << workArea; // FIXME: we use an internal class declared in a private header here, which is pretty bad. QSize grid = listView_->gridSize(); QPoint pos = workArea.topLeft(); for(; row < rowCount; ++row) { QModelIndex index = proxyModel_->index(row, 0); int itemWidth = delegate_->sizeHint(listView_->getViewOptions(), index).width(); FmFileInfo* file = proxyModel_->fileInfoFromIndex(index); QByteArray name = fm_file_info_get_name(file); QHash<QByteArray, QPoint>::iterator it = customItemPos_.find(name); if(it != customItemPos_.end()) { // the item has a custom position QPoint customPos = *it; // center the contents vertically listView_->setPositionForIndex(customPos + QPoint((grid.width() - itemWidth) / 2, 0), index); // qDebug() << "set custom pos:" << name << row << index << customPos; continue; } // check if the current pos is alredy occupied by a custom item bool used = false; for(it = customItemPos_.begin(); it != customItemPos_.end(); ++it) { QPoint customPos = *it; if(QRect(customPos, grid).contains(pos)) { used = true; break; } } if(used) { // go to next pos --row; } else { // center the contents vertically listView_->setPositionForIndex(pos + QPoint((grid.width() - itemWidth) / 2, 0), index); // qDebug() << "set pos" << name << row << index << pos; } // move to next cell in the column pos.setY(pos.y() + grid.height() + listView_->spacing()); if(pos.y() + grid.height() > workArea.bottom() + 1) { // if the next position may exceed the bottom of work area, go to the top of next column pos.setX(pos.x() + grid.width() + listView_->spacing()); pos.setY(workArea.top()); // check if the new column exceeds the right margin of work area if(pos.x() + grid.width() > workArea.right() + 1) { if(desktop->isVirtualDesktop()) { // in virtual desktop mode, go to next screen ++screen; break; } } } } if(row >= rowCount) break; } }