예제 #1
0
/*****************************************************************************************
 *  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;
}
예제 #2
0
// special thanks to Razor-qt developer Alec Moskvin(amoskvin) for providing the fix!
void FolderItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
  Q_ASSERT(index.isValid());
  FmFileInfo* file = static_cast<FmFileInfo*>(index.data(FolderModel::FileInfoRole).value<void*>());
  bool isSymlink = file && fm_file_info_is_symlink(file);

  if(option.decorationPosition == QStyleOptionViewItem::Top ||
    option.decorationPosition == QStyleOptionViewItem::Bottom) {
    painter->save();
    painter->setClipRect(option.rect);

    QStyleOptionViewItemV4 opt = option;
    initStyleOption(&opt, index);
    opt.decorationAlignment = Qt::AlignHCenter|Qt::AlignTop;
    opt.displayAlignment = Qt::AlignTop|Qt::AlignHCenter;

    // draw the icon
    QIcon::Mode iconMode = iconModeFromState(opt.state);
    QPoint iconPos(opt.rect.x() + (opt.rect.width() - opt.decorationSize.width()) / 2, opt.rect.y());
    QPixmap pixmap = opt.icon.pixmap(opt.decorationSize, iconMode);
    painter->drawPixmap(iconPos, pixmap);

    // draw some emblems for the item if needed
    // we only support symlink emblem at the moment
    if(isSymlink)
      painter->drawPixmap(iconPos, symlinkIcon_.pixmap(opt.decorationSize / 2, iconMode));

    // draw the text
    // The text rect dimensions should be exactly as they were in sizeHint()
    QRectF textRect(opt.rect.x() - (gridSize_.width() - opt.rect.width()) / 2,
                    opt.rect.y() + opt.decorationSize.height(),
                    gridSize_.width(),
                    gridSize_.height() - opt.decorationSize.height());
    drawText(painter, opt, textRect);
    painter->restore();
  }
  else {
    // let QStyledItemDelegate does its default painting
    QStyledItemDelegate::paint(painter, option, index);

    // draw emblems if needed
    if(isSymlink) {
      QStyleOptionViewItemV4 opt = option;
      initStyleOption(&opt, index);
      QIcon::Mode iconMode = iconModeFromState(opt.state);
      QPoint iconPos(opt.rect.x(), opt.rect.y() + (opt.rect.height() - opt.decorationSize.height()) / 2);
      // draw some emblems for the item if needed
      // we only support symlink emblem at the moment
      painter->drawPixmap(iconPos, symlinkIcon_.pixmap(opt.decorationSize / 2, iconMode));
    }
  }
}
예제 #3
0
파일: tab-page.c 프로젝트: geekless/pcmanfm
static void on_folder_view_sel_changed(FmFolderView* fv, FmFileInfoList* files, FmTabPage* page)
{
    char* msg = page->status_text[FM_STATUS_TEXT_SELECTED_FILES];
    g_free(msg);
    msg = NULL;

    // use SI metric by default
    static gboolean use_si_prefix = TRUE ;

    unsigned items_num = 0;

    if (files)
        items_num = fm_list_get_length(files) ;

    if (items_num > 1) // multiple items are selected
    {
        goffset items_totalsize = 0 ;

        // whether selected items contain dir
        gboolean items_contain_dir  = FALSE ;

        GList* l;
        for (l=fm_list_peek_head_link(files);l;l=l->next)
        {
            FmFileInfo* fi = (FmFileInfo*)l->data;

            // ignore dir when calculating total size. because that
            // may take a long long time, not suitable for updating
            // statusbar in real time.
            if (fm_file_info_is_dir(fi) )
            {
                items_contain_dir = TRUE;
            }
            else
            {
                // Non-dir items are regard as files
                // Should extra logic be added for different kinds of files?
                // hardlink, symlink, pipe, socket ?
                items_totalsize += fm_file_info_get_size(fi) ;
            }
        }

        // when the selected items contain dir, do not show size info on the
        // statusbar, because the calculated total size counts for files only
        // and showing it would be misleading to the user.
        if (items_contain_dir)
        {
            msg = g_strdup_printf("%d items selected", items_num);
        }
        else
        {
            char items_totalsize_str[ 64 ];
            fm_file_size_to_str( items_totalsize_str, items_totalsize, use_si_prefix );

            msg = g_strdup_printf("%d items selected, total size: %s", \
                                  items_num, items_totalsize_str);
        }

    }
    else if (items_num == 1)
    {
        FmFileInfo* fi = fm_list_peek_head(files);
        const char* size_str = fm_file_info_get_disp_size(fi);
        gboolean is_link = fm_file_info_is_symlink(fi);
        if (is_link && size_str)
        {
            msg = g_strdup_printf("\"%s\" link to \"%s\" (%s)",
                                  fm_file_info_get_disp_name(fi),
                                  fm_file_info_get_target(fi),
                                  size_str);
        }
        else if (is_link)
        {
            msg = g_strdup_printf("\"%s\" link to \"%s\"",
                                  fm_file_info_get_disp_name(fi),
                                  fm_file_info_get_target(fi));
        }
        else if (size_str)
        {
            msg = g_strdup_printf("\"%s\" (%s) %s",
                                  fm_file_info_get_disp_name(fi),
                                  size_str,
                                  fm_file_info_get_desc(fi));
        }
        else
        {
            msg = g_strdup_printf("\"%s\" %s",
                                  fm_file_info_get_disp_name(fi),
                                  fm_file_info_get_desc(fi));
        }
    }

    page->status_text[FM_STATUS_TEXT_SELECTED_FILES] = msg;
    g_signal_emit(page, signals[STATUS], 0,
                  (guint)FM_STATUS_TEXT_SELECTED_FILES, msg);
}
예제 #4
0
void FilePropsDialog::initGeneralPage() {
  // update UI
  if(singleType) { // all files are of the same mime-type
    FmIcon* icon = NULL;
    // FIXME: handle custom icons for some files
    // FIXME: display special property pages for special files or
    // some specified mime-types.
    if(singleFile) { // only one file is selected.
      icon = fm_file_info_get_icon(fileInfo);
    }
    if(mimeType) {
      if(!icon) // get an icon from mime type if needed
        icon = fm_mime_type_get_icon(mimeType);
      ui->fileType->setText(QString::fromUtf8(fm_mime_type_get_desc(mimeType)));
      ui->mimeType->setText(QString::fromUtf8(fm_mime_type_get_type(mimeType)));
    }
    if(icon) {
      ui->iconButton->setIcon(IconTheme::icon(icon));
    }

    if(singleFile && fm_file_info_is_symlink(fileInfo)) {
      ui->target->setText(QString::fromUtf8(fm_file_info_get_target(fileInfo)));
    }
    else {
      ui->target->hide();
      ui->targetLabel->hide();
    }
  } // end if(singleType)
  else { // not singleType, multiple files are selected at the same time
    ui->fileType->setText(tr("Files of different types"));
    ui->target->hide();
    ui->targetLabel->hide();
  }

  // FIXME: check if all files has the same parent dir, mtime, or atime
  if(singleFile) { // only one file is selected
    FmPath* parent_path = fm_path_get_parent(fm_file_info_get_path(fileInfo));
    char* parent_str = parent_path ? fm_path_display_name(parent_path, true) : NULL;

    ui->fileName->setText(QString::fromUtf8(fm_file_info_get_disp_name(fileInfo)));
    if(parent_str) {
      ui->location->setText(QString::fromUtf8(parent_str));
      g_free(parent_str);
    }
    else
      ui->location->clear();

    ui->lastModified->setText(QString::fromUtf8(fm_file_info_get_disp_mtime(fileInfo)));

    // FIXME: need to encapsulate this in an libfm API.
    time_t atime;
    struct tm tm;
    atime = fm_file_info_get_atime(fileInfo);
    localtime_r(&atime, &tm);
    char buf[128];
    strftime(buf, sizeof(buf), "%x %R", &tm);
    ui->lastAccessed->setText(QString::fromUtf8(buf));
  }
  else {
    ui->fileName->setText(tr("Multiple Files"));
    ui->fileName->setEnabled(false);
  }

  initApplications(); // init applications combo box

  // calculate total file sizes
  fileSizeTimer = new QTimer(this);
  connect(fileSizeTimer, &QTimer::timeout, this, &FilePropsDialog::onFileSizeTimerTimeout);
  fileSizeTimer->start(600);
  g_signal_connect(deepCountJob, "finished", G_CALLBACK(onDeepCountJobFinished), this);
  gboolean ret = fm_job_run_async(FM_JOB(deepCountJob));
}
예제 #5
0
void fm_folder_model_get_value(GtkTreeModel *tree_model,
                               GtkTreeIter *iter,
                               gint column,
                               GValue *value)
{
    GSequenceIter* item_it;
    FmFolderModel* model = FM_FOLDER_MODEL(tree_model);

    g_return_if_fail(iter != NULL);
    g_return_if_fail( column < G_N_ELEMENTS(column_types) );

    g_value_init(value, column_types[column]);

    item_it = (GSequenceIter*)iter->user_data;
    g_return_if_fail(item_it != NULL);

    FmFolderItem* item = (FmFolderItem*)g_sequence_get(item_it);
    FmFileInfo* info = item->inf;

    switch( column )
    {
    case COL_FILE_GICON:
        g_value_set_object(value, info->icon->gicon);
        break;
    case COL_FILE_ICON:
    {
        if( G_UNLIKELY(!item->icon) )
        {
            if( !info->icon )
                return;
            item->icon = fm_icon_get_pixbuf(info->icon, model->icon_size);
        }

        /* if we want to show a thumbnail */
        /* if we're on local filesystem or thumbnailing for remote files is allowed */
        if(fm_config->show_thumbnail && (fm_path_is_local(item->inf->path) || !fm_config->thumbnail_local))
        {
            if(!item->is_thumbnail && !item->thumbnail_failed && !item->thumbnail_loading)
            {
                if(fm_file_info_can_thumbnail(item->inf))
                {
                    if(item->inf->size > 0 && (fm_config->thumbnail_max == 0 || item->inf->size <= (fm_config->thumbnail_max << 10)))
                    {
                        GdkPixbuf * pix = fm_thumbnail_try_read_from_cache(item->inf, model->icon_size);
                        if (pix)
                        {
                           if (item->icon)
                               g_object_unref(item->icon);
                           item->icon = pix;
                           item->is_thumbnail = TRUE;
                        }
                        else
                        {
                            FmThumbnailRequest* req = fm_thumbnail_request2(item->inf, model->icon_size, on_thumbnail_loaded, model, item->iter_age, item);
                            model->thumbnail_requests = g_list_prepend(model->thumbnail_requests, req);
                            item->thumbnail_loading = TRUE;
                        }
                    }
                }
                else
                {
                    item->thumbnail_failed = TRUE;
                }
            }
        }

        g_value_set_object(value, item->icon);
        
        break;
    }
    case COL_FILE_NAME:
        g_value_set_string(value, info->disp_name);
        break;
    case COL_FILE_NAME_HINT_SIZE:
    case COL_FILE_NAME_HINT_MTIME:
    case COL_FILE_NAME_HINT_DESC:
    {
        //g_value_set_string(value, info->disp_name);
        if (!item->hinted_disp_name || item->hint_column != column)
        {
            item->hint_column != column;
            if (item->hinted_disp_name)
                g_free(item->hinted_disp_name);

            gchar * s = NULL;
            if (fm_file_info_is_symlink(info))
                s = fm_file_info_get_target(info);
            if (!s)
            {
                switch (column)
                {
                    case COL_FILE_NAME_HINT_SIZE:
                        s = fm_file_info_get_disp_size(info);
                        break;
                    case COL_FILE_NAME_HINT_MTIME:
                        s = fm_file_info_get_disp_mtime(info);
                        break;
                    case COL_FILE_NAME_HINT_DESC:
                        s = fm_file_info_get_desc(info);
                        break;
                }
            }
            if (!s)
                s = fm_file_info_get_desc(info);
            if (!s)
                s = "";
            item->hinted_disp_name = g_markup_printf_escaped("%s<span size='small'>\n<i>%s</i></span>", info->disp_name, s);
        }
        g_value_set_string(value, item->hinted_disp_name);
        break;
    }
    case COL_FILE_SIZE:
        g_value_set_string( value, fm_file_info_get_disp_size(info) );
        break;
    case COL_FILE_DESC:
        g_value_set_string( value, fm_file_info_get_desc(info) );
        break;
    case COL_FILE_PERM:
//        g_value_set_string( value, fm_file_info_get_disp_perm(info) );
        break;
    case COL_FILE_OWNER:
//        g_value_set_string( value, fm_file_info_get_disp_owner(info) );
        break;
    case COL_FILE_MTIME:
        g_value_set_string( value, fm_file_info_get_disp_mtime(info) );
        break;
    case COL_FILE_INFO:
        g_value_set_pointer(value, info);
        break;
    }
}
예제 #6
0
/**
 * fm_launch_files
 * @ctx: (allow-none): a launch context
 * @file_infos: (element-type FmFileInfo): files to launch
 * @launcher: #FmFileLauncher with callbacks
 * @user_data: data supplied for callbacks
 *
 * Launches files using callbacks in @launcher.
 *
 * Returns: %TRUE in case of success.
 *
 * Since: 0.1.0
 */
gboolean fm_launch_files(GAppLaunchContext* ctx, GList* file_infos, FmFileLauncher* launcher, gpointer user_data)
{
    GList* l;
    GHashTable* hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
    GList *folders = NULL;
    FmFileInfo* fi;
    GList *targets = NULL;
    GError* err = NULL;
    GAppInfo* app;
    const char* type;

    for(l = file_infos; l; l=l->next)
    {
        GList* fis;
        char *filename, *scheme;
        const char *target = NULL;

        fi = (FmFileInfo*)l->data;
        /* special handling for shortcuts */
        if (!fm_file_info_is_symlink(fi))
            /* symlinks also has fi->target, but we only handle shortcuts here. */
            target = fm_file_info_get_target(fi);
        if (launcher->open_folder && fm_file_info_is_dir(fi))
        {
            /* special handling for shortcuts */
            if(target)
            {
                fi = _fetch_file_info_for_shortcut(fm_file_info_get_target(fi),
                                                   ctx, launcher, user_data);
                if (fi == NULL)
                    /* error was shown by job already */
                    continue;
                targets = g_list_prepend(targets, fi);
            }
            folders = g_list_prepend(folders, fi);
        }
        else if (fm_file_info_is_desktop_entry(fi))
        {
_launch_desktop_entry:
            if (!target)
                filename = fm_path_to_str(fm_file_info_get_path(fi));
            fm_launch_desktop_entry(ctx, target ? target : filename, NULL,
                                    launcher, user_data);
            if (!target)
                g_free(filename);
            continue;
        }
        else
        {
            FmPath* path = fm_file_info_get_path(fi);
            FmMimeType* mime_type = NULL;
            if(fm_path_is_native(path))
            {
                /* special handling for shortcuts */
                if (target)
                {
                    if (fm_file_info_get_mime_type(fi) == _fm_mime_type_get_inode_x_shortcut())
                    /* if we already know MIME type then use it instead */
                    {
                      scheme = g_uri_parse_scheme(target);
                      if (scheme)
                      {
                        /* FIXME: this is rough! */
                        if (strcmp(scheme, "file") != 0 &&
                            strcmp(scheme, "trash") != 0 &&
                            strcmp(scheme, "network") != 0 &&
                            strcmp(scheme, "computer") != 0 &&
                            strcmp(scheme, "menu") != 0)
                        {
                            /* we don't support this URI internally, try GIO */
                            app = g_app_info_get_default_for_uri_scheme(scheme);
                            if (app)
                            {
                                fis = g_list_prepend(NULL, (char *)target);
                                fm_app_info_launch_uris(app, fis, ctx, &err);
                                g_list_free(fis);
                                g_object_unref(app);
                            }
                            else if (launcher->error)
                                g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED,
                                            _("No default application is set to launch URIs %s://"),
                                            scheme);
                            if (err)
                            {
                                launcher->error(ctx, err, NULL, user_data);
                                g_clear_error(&err);
                            }
                            g_free(scheme);
                            continue;
                        }
                        g_free(scheme);
                      }
                    }
                    else
                        mime_type = fm_file_info_get_mime_type(fi);
                    /* retrieve file info for target otherwise and handle it */
                    fi = _fetch_file_info_for_shortcut(target, ctx, launcher, user_data);
                    if (fi == NULL)
                        /* error was shown by job already */
                        continue;
                    targets = g_list_prepend(targets, fi);
                    path = fm_file_info_get_path(fi);
                    /* special handling for desktop entries */
                    if (fm_file_info_is_desktop_entry(fi))
                        goto _launch_desktop_entry;
                }
                if(fm_file_info_is_executable_type(fi))
                {
                    /* if it's an executable file, directly execute it. */
                    filename = fm_path_to_str(path);

                    /* FIXME: we need to use eaccess/euidaccess here. */
                    if(g_file_test(filename, G_FILE_TEST_IS_EXECUTABLE))
                    {
                        if(launcher->exec_file)
                        {
                            FmFileLauncherExecAction act = launcher->exec_file(fi, user_data);
                            GAppInfoCreateFlags flags = 0;
                            switch(act)
                            {
                            case FM_FILE_LAUNCHER_EXEC_IN_TERMINAL:
                                flags |= G_APP_INFO_CREATE_NEEDS_TERMINAL;
                                /* NOTE: no break here */
                            case FM_FILE_LAUNCHER_EXEC:
                            {
                                /* filename may contain spaces. Fix #3143296 */
                                char* quoted = g_shell_quote(filename);
                                app = fm_app_info_create_from_commandline(quoted, NULL, flags, NULL);
                                g_free(quoted);
                                if(app)
                                {
                                    char* run_path = g_path_get_dirname(filename);
                                    char* cwd = NULL;
                                    /* bug #3589641: scripts are ran from $HOME.
                                       since GIO launcher is kinda ugly - it has
                                       no means to set running directory so we
                                       do workaround - change directory to it */
                                    if(run_path && strcmp(run_path, "."))
                                    {
                                        cwd = g_get_current_dir();
                                        if(chdir(run_path) != 0)
                                        {
                                            g_free(cwd);
                                            cwd = NULL;
                                            if (launcher->error)
                                            {
                                                g_set_error(&err, G_IO_ERROR,
                                                            g_io_error_from_errno(errno),
                                                            _("Cannot set working directory to '%s': %s"),
                                                            run_path, g_strerror(errno));
                                                launcher->error(ctx, err, NULL, user_data);
                                                g_clear_error(&err);
                                            }
                                        }
                                    }
                                    g_free(run_path);
                                    if(!fm_app_info_launch(app, NULL, ctx, &err))
                                    {
                                        if(launcher->error)
                                            launcher->error(ctx, err, NULL, user_data);
                                        g_error_free(err);
                                        err = NULL;
                                    }
                                    if(cwd) /* return back */
                                    {
                                        if(chdir(cwd) != 0)
                                            g_warning("fm_launch_files(): chdir() failed");
                                        g_free(cwd);
                                    }
                                    g_object_unref(app);
                                    continue;
                                }
                                break;
                            }
                            case FM_FILE_LAUNCHER_EXEC_OPEN:
                                break;
                            case FM_FILE_LAUNCHER_EXEC_CANCEL:
                                continue;
                            }
                        }
                    }
                    g_free(filename);
                }
            }
            if (mime_type == NULL)
                mime_type = fm_file_info_get_mime_type(fi);
            if(mime_type && (type = fm_mime_type_get_type(mime_type)))
            {
                fis = g_hash_table_lookup(hash, type);
                fis = g_list_prepend(fis, fi);
                g_hash_table_insert(hash, (gpointer)type, fis);
            }
            else if (launcher->error)
            {
                g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED,
                            _("Could not determine content type of file '%s' to launch it"),
                            fm_file_info_get_disp_name(fi));
                launcher->error(ctx, err, NULL, user_data);
                g_clear_error(&err);
            }
        }
    }

    if(g_hash_table_size(hash) > 0)
    {
        GHashTableIter it;
        GList* fis;
        g_hash_table_iter_init(&it, hash);
        while(g_hash_table_iter_next(&it, (void**)&type, (void**)&fis))
        {
            GAppInfo* app = g_app_info_get_default_for_type(type, FALSE);
            if(!app)
            {
                if(launcher->get_app)
                {
                    FmMimeType* mime_type = fm_file_info_get_mime_type((FmFileInfo*)fis->data);
                    app = launcher->get_app(fis, mime_type, user_data, NULL);
                }
            }
            if(app)
            {
                for(l=fis; l; l=l->next)
                {
                    char* uri;
                    fi = (FmFileInfo*)l->data;
                    /* special handling for shortcuts */
                    if (fm_file_info_is_shortcut(fi))
                        uri = g_strdup(fm_file_info_get_target(fi));
                    else
                        uri = fm_path_to_uri(fm_file_info_get_path(fi));
                    l->data = uri;
                }
                fis = g_list_reverse(fis);
                fm_app_info_launch_uris(app, fis, ctx, &err);
                /* free URI strings */
                g_list_foreach(fis, (GFunc)g_free, NULL);
                g_object_unref(app);
            }
            else if (launcher->error)
                g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED,
                            _("No default application is set for MIME type %s"),
                            type);
            if (err)
            {
                launcher->error(ctx, err, NULL, user_data);
                g_clear_error(&err);
            }
            g_list_free(fis);
        }
    }
    g_hash_table_destroy(hash);

    if(folders)
    {
        folders = g_list_reverse(folders);
        if(launcher->open_folder)
        {
            launcher->open_folder(ctx, folders, user_data, &err);
            if(err)
            {
                if(launcher->error)
                    launcher->error(ctx, err, NULL, user_data);
                g_error_free(err);
                err = NULL;
            }
        }
        g_list_free(folders);
    }
    g_list_free_full(targets, (GDestroyNotify)fm_file_info_unref);
    return TRUE;
}
예제 #7
0
static void update_ui (FmFilePropData *data)
{
    GtkImage *img =  (GtkImage*) data->icon;

    if ( data->single_type ) // all files are of the same mime-type
    {
        GIcon *icon = NULL;
        // FIXME_pcm: handle custom icons for some files

        /* FIXME_pcm: display special property pages for special files or
         * some specified mime-types. */
        if ( data->single_file ) // only one file is selected.
        {
            FmFileInfo *file_info =  (FmFileInfo*)fm_list_peek_head (data->files);

            icon = fm_file_info_get_gicon (file_info);
        }

        if (data->mime_type)
        {
            if (!icon)
            {
                FmIcon *ficon = fm_mime_type_get_icon (data->mime_type);
                if (ficon)
                    icon = ficon->gicon;
            }
            gtk_label_set_text (GTK_LABEL (data->type), fm_mime_type_get_desc (data->mime_type));
        }

        if (icon)
            gtk_image_set_from_gicon (img, icon, GTK_ICON_SIZE_DIALOG);

        if ( data->single_file && fm_file_info_is_symlink (data->file_info) )
        {
            gtk_widget_show (data->target_label);
            gtk_widget_show (data->target);
            gtk_label_set_text (GTK_LABEL (data->target), fm_file_info_get_target (data->file_info));

            // gtk_label_set_text (data->type, fm_mime_type_get_desc (data->mime_type));
        }
        else
        {
            gtk_widget_destroy (data->target_label);
            gtk_widget_destroy (data->target);
        }
    }
    else
    {
        gtk_image_set_from_stock (img, GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_DIALOG);
        gtk_widget_set_sensitive (data->name, FALSE);

        gtk_label_set_text (GTK_LABEL (data->type), _("Files of different types"));

        gtk_widget_destroy (data->target_label);
        gtk_widget_destroy (data->target);

        gtk_widget_destroy (data->open_with_label);
        gtk_widget_destroy (data->open_with);
        data->open_with = data->open_with_label = NULL;
    }

    // FIXME_pcm: check if all files has the same parent dir, mtime, or atime
    if ( data->single_file )
    {
        char buf[128];
        FmPath *parent = fm_path_get_parent (fm_file_info_get_path (data->file_info));
        char *parent_str = parent ? fm_path_display_name (parent, TRUE) : NULL;
        gtk_entry_set_text (GTK_ENTRY (data->name), fm_file_info_get_disp_name (data->file_info));
        if (parent_str)
        {
            gtk_label_set_text (GTK_LABEL (data->dir), parent_str);
            g_free (parent_str);
        }
        else
            gtk_label_set_text (GTK_LABEL (data->dir), "");
        gtk_label_set_text (GTK_LABEL (data->mtime), fm_file_info_get_disp_mtime (data->file_info));

        // FIXME_pcm: need to encapsulate this in an libfm API.
        strftime ( buf, sizeof ( buf ),
                   "%x %R",
                   localtime ( &data->file_info->atime ) );
        gtk_label_set_text (GTK_LABEL (data->atime), buf);
    }
    else
    {
        gtk_entry_set_text (GTK_ENTRY (data->name), _("Multiple Files"));
        gtk_widget_set_sensitive (data->name, FALSE);
    }

    update_permissions (data);

    on_timeout (data);
}