i've started working on a file search for muc, and hav a few questions about the right/good way to implement this.
Currently there are the following new classes:
com.mucommander.file
FileFinder:
A class to do the searching stuff. It has two public static methods:
public static void findFiles(AbstractFile startDirectory, FileFilter filter, FileFoundListener listener);
and
public static void findFiles(AbstractFile startDirectory, Collection fileFilters, FileFoundListener listener);
It uses exactly one (or a collection of) com.mucommander.file.filter.*. Currently only the
RegexpFilenameFilter has been tested, but the others should work too.
FileFoundLister:
An interface with a single method wich get called if a AbstractFile has passed one of the used filters.
com.mucommander.ui.main.menu.MainMenuBar
New entry in the "file" menu for the search dialog
com.mucommander.ui.action.OpenSearchDialogAction:
An Action to open the SearchDialog (Is it really necessary to create new class for just calling new
SearchDialog().showDialog()?)
com.mucommanderui.dialog.SearchDialog
The search dialog. Up to now the GUI stuff is crappy netbeans generated code - i was too lazy yesterday to
write this by hand ;)
The SearchDialog has two inner classes: The search thread and a ListModel. Both should be moved to an own
class (at least the Thread).
Is there a common way in mucommander to implement a background job? Yes, ive seen the com.mucommander.job
thing, but it seems that all of these jobs are using a ProgressDialog?
The "feature plan":
- "Standard" file search: Search all files containing the search phrase in there path or filename (uses a
RegexpFilenameFilter with ".*" + searchPhrase + ".*". This is a bit dangerous, since a user may enter
blah.zip, and the RegexpFilenameFilter would interpret the dot as "any char".
- RegEx search: Use the regex entered Regex and the RegexpFilenameFilter.
- (later) search in selected dirs (is there a way to get all selected elements in a Panel?)
- (later) search in archives
- (later) search files containing <text>
- (more later) filter files according there size/date
Any suggestions/feedback/wishes for the implementation?
Johann
--
Johann Schmitz
http://www.j-schmitz.net
public static void findFiles(AbstractFileList oldSearch, Collection fileFilters, FileFoundListener listener);
And, if you do that, there will be possibility to "Save Search" result.
For "find string x" i have a FileContentFileFilter (extending com.mucommander.file.filter.FileFilter) in mind,
since multiple Filters are combined with "and".
> And, if you do that, there will be possibility to "Save Search" result.
Hm. You mean something like the virtual folders feature of IMAP-Mailboxes?
That for I think
AbstractFileList should fit :)
Anyway, that's only recommendation, you're the boss ;)
changes in: com.mucommander.file.AbstractFile.java
1326 line
public boolean equals(Object f) {
if(f==null || !(f instanceof AbstractFile))
return false;
return hashCode() == f.hashCode();
}
// Flag, if we already caluclated hashcode
private boolean hashCalced = false;
// Cached Hashcode itself
private int hCode = 0;
/**
* Returns the hashCode of this file's {@link #getURL() URL}.
*
* @return the hashCode of this file's {@link #getURL() URL}.
*/
public int hashCode() {
if(!hashCalced)
{
//not sure if this OK without synchronized
hashCalced = true;
hCode = getCanonicalPath(false).hashCode();
}
return hCode;
}
and in com.mucommander.file.impl.local.LocalFile.java
394 line
public static Vector cachedJavaIoRoots = new Vector();
/**
* Resolves and returns all local volumes:
* <ul>
* <li>On UNIX-based OSes, these are the mount points declared in
<code>/etc/ftab</code>.</li>
* <li>On the Windows platform, these are the drives displayed in
Explorer. Some of the returned volumes may
* correspond to removable drives and thus may not always be
available -- if they aren't, {@link #exists()} will
* return <code>false</code>.</li>
* </ul>
* <p>
* The return list of volumes is purposively not cached so that new
volumes will be returned as soon as they are
* mounted.
* </p>
*
* @return all local volumes
*/
public static AbstractFile[] getVolumes() {
Vector volumesV = new Vector();
// Add Mac OS X's /Volumes subfolders and not file roots ('/')
since Volumes already contains a named link
// (like 'Hard drive' or whatever silly name the user gave his
primary hard disk) to /
if(OsFamilies.MAC_OS_X.isCurrent()) {
addMacOSXVolumes(volumesV);
}
else {
// Add java.io.File's root folders
File[] files = File.listRoots();
boolean needRebuildCachedRoots =
cachedJavaIoRoots.isEmpty() || files.length != cachedJavaIoRoots.size();
if(!needRebuildCachedRoots)
{
//simply checking every exist roots;
for (int i = 0; !needRebuildCachedRoots && i <
files.length; i++)
{
File file = files[i];
boolean found = false;
for (int j = 0; !found && j <
cachedJavaIoRoots.size(); j++)
{
AbstractFile abstractFile = (AbstractFile)
cachedJavaIoRoots.elementAt(j);
if(abstractFile.toString().equals(file.toString()))
{
found = true;
}
}
needRebuildCachedRoots = !found;
}
}
if(needRebuildCachedRoots)
{
cachedJavaIoRoots.clear();
addJavaIoFileRoots(cachedJavaIoRoots);
}
volumesV.addAll(cachedJavaIoRoots);
// Add /etc/fstab folders under UNIX-based systems.
if(OsFamily.getCurrent().isUnixBased())
addFstabEntries(volumesV);
}
// Add home folder, if it is not already present in the list
AbstractFile homeFolder = getUserHome();
if(!(homeFolder==null || volumesV.contains(homeFolder)))
volumesV.add(homeFolder);
AbstractFile volumes[] = new AbstractFile[volumesV.size()];
volumesV.toArray(volumes);
return volumes;
}