Added methods to delete songs and song groups.
- OsuGroupList.get().deleteSongGroup() will delete a song group from the list. - OsuGroupList.get().deleteSong() will delete an individual song from the list (must be expanded), and will delete the song group if there are no remaining songs in the group. - If possible, deleted beatmap files are moved to system trash (using JNA); otherwise, they are deleted immediately. This is done through Utils.deleteToTrash(). Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
484bb1ba31
commit
b69ff68d7c
10
pom.xml
10
pom.xml
|
@ -143,5 +143,15 @@
|
||||||
<artifactId>json</artifactId>
|
<artifactId>json</artifactId>
|
||||||
<version>20140107</version>
|
<version>20140107</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.java.dev.jna</groupId>
|
||||||
|
<artifactId>jna</artifactId>
|
||||||
|
<version>4.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.java.dev.jna</groupId>
|
||||||
|
<artifactId>jna-platform</artifactId>
|
||||||
|
<version>4.1.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -262,9 +262,9 @@ public class OsuFile implements Comparable<OsuFile> {
|
||||||
try {
|
try {
|
||||||
Image bgImage = bgImageMap.get(this);
|
Image bgImage = bgImageMap.get(this);
|
||||||
if (bgImage == null) {
|
if (bgImage == null) {
|
||||||
bgImage = new Image(bg);
|
|
||||||
if (bgImageMap.size() > MAX_CACHE_SIZE)
|
if (bgImageMap.size() > MAX_CACHE_SIZE)
|
||||||
clearImageCache();
|
clearImageCache();
|
||||||
|
bgImage = new Image(bg);
|
||||||
bgImageMap.put(this, bgImage);
|
bgImageMap.put(this, bgImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu;
|
package itdelatrisu.opsu;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -54,6 +58,9 @@ public class OsuGroupList {
|
||||||
/** Index of current expanded node (-1 if no node is expanded). */
|
/** Index of current expanded node (-1 if no node is expanded). */
|
||||||
private int expandedIndex;
|
private int expandedIndex;
|
||||||
|
|
||||||
|
/** Start and end nodes of expanded group. */
|
||||||
|
private OsuGroupNode expandedStartNode, expandedEndNode;
|
||||||
|
|
||||||
/** The last search query. */
|
/** The last search query. */
|
||||||
private String lastQuery;
|
private String lastQuery;
|
||||||
|
|
||||||
|
@ -83,6 +90,7 @@ public class OsuGroupList {
|
||||||
public void reset() {
|
public void reset() {
|
||||||
nodes = parsedNodes;
|
nodes = parsedNodes;
|
||||||
expandedIndex = -1;
|
expandedIndex = -1;
|
||||||
|
expandedStartNode = expandedEndNode = null;
|
||||||
lastQuery = "";
|
lastQuery = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +117,123 @@ public class OsuGroupList {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a song group from the list, and also deletes the beatmap
|
||||||
|
* directory associated with the node.
|
||||||
|
* @param node the node containing the song group to delete
|
||||||
|
* @return true if the song group was deleted, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean deleteSongGroup(OsuGroupNode node) {
|
||||||
|
if (node == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// re-link base nodes
|
||||||
|
int index = node.index;
|
||||||
|
OsuGroupNode ePrev = getBaseNode(index - 1), eCur = getBaseNode(index), eNext = getBaseNode(index + 1);
|
||||||
|
if (ePrev != null) {
|
||||||
|
if (ePrev.index == expandedIndex)
|
||||||
|
expandedEndNode.next = eNext;
|
||||||
|
else if (eNext != null && eNext.index == expandedIndex)
|
||||||
|
ePrev.next = expandedStartNode;
|
||||||
|
else
|
||||||
|
ePrev.next = eNext;
|
||||||
|
}
|
||||||
|
if (eNext != null) {
|
||||||
|
if (eNext.index == expandedIndex)
|
||||||
|
expandedStartNode.prev = ePrev;
|
||||||
|
else if (ePrev != null && ePrev.index == expandedIndex)
|
||||||
|
eNext.prev = expandedEndNode;
|
||||||
|
else
|
||||||
|
eNext.prev = ePrev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all node references
|
||||||
|
OsuFile osu = node.osuFiles.get(0);
|
||||||
|
nodes.remove(index);
|
||||||
|
parsedNodes.remove(eCur);
|
||||||
|
mapCount -= node.osuFiles.size();
|
||||||
|
if (osu.beatmapSetID > 0)
|
||||||
|
MSIDdb.remove(osu.beatmapSetID);
|
||||||
|
|
||||||
|
// reset indices
|
||||||
|
for (int i = index, size = size(); i < size; i++)
|
||||||
|
nodes.get(i).index = i;
|
||||||
|
if (index == expandedIndex) {
|
||||||
|
expandedIndex = -1;
|
||||||
|
expandedStartNode = expandedEndNode = null;
|
||||||
|
} else if (expandedIndex > index) {
|
||||||
|
expandedIndex--;
|
||||||
|
OsuGroupNode expandedNode = expandedStartNode;
|
||||||
|
for (int i = 0, size = expandedNode.osuFiles.size();
|
||||||
|
i < size && expandedNode != null;
|
||||||
|
i++, expandedNode = expandedNode.next)
|
||||||
|
expandedNode.index = expandedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop playing the track
|
||||||
|
File dir = osu.getFile().getParentFile();
|
||||||
|
if (MusicController.trackExists() || MusicController.isTrackLoading()) {
|
||||||
|
File audioFile = MusicController.getOsuFile().audioFilename;
|
||||||
|
if (audioFile != null && audioFile.equals(osu.audioFilename)) {
|
||||||
|
MusicController.reset();
|
||||||
|
System.gc(); // TODO: why can't files be deleted without calling this?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the associated directory
|
||||||
|
try {
|
||||||
|
Utils.deleteToTrash(dir);
|
||||||
|
} catch (IOException e) {
|
||||||
|
ErrorHandler.error("Could not delete song group.", e, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a song from a song group, and also deletes the beatmap file.
|
||||||
|
* If this causes the song group to be empty, then the song group and
|
||||||
|
* beatmap directory will be deleted altogether.
|
||||||
|
* @param node the node containing the song group to delete (expanded only)
|
||||||
|
* @return true if the song or song group was deleted, false otherwise
|
||||||
|
* @see #deleteSongGroup(OsuGroupNode)
|
||||||
|
*/
|
||||||
|
public boolean deleteSong(OsuGroupNode node) {
|
||||||
|
if (node == null || node.osuFileIndex == -1 || node.index != expandedIndex)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// last song in group?
|
||||||
|
int size = node.osuFiles.size();
|
||||||
|
if (node.osuFiles.size() == 1)
|
||||||
|
return deleteSongGroup(node);
|
||||||
|
|
||||||
|
// reset indices
|
||||||
|
OsuGroupNode expandedNode = node.next;
|
||||||
|
for (int i = node.osuFileIndex + 1;
|
||||||
|
i < size && expandedNode != null && expandedNode.index == node.index;
|
||||||
|
i++, expandedNode = expandedNode.next)
|
||||||
|
expandedNode.osuFileIndex--;
|
||||||
|
|
||||||
|
// remove song reference
|
||||||
|
OsuFile osu = node.osuFiles.remove(node.osuFileIndex);
|
||||||
|
mapCount--;
|
||||||
|
|
||||||
|
// re-link nodes
|
||||||
|
if (node.prev != null)
|
||||||
|
node.prev.next = node.next;
|
||||||
|
if (node.next != null)
|
||||||
|
node.next.prev = node.prev;
|
||||||
|
|
||||||
|
// delete the associated file
|
||||||
|
try {
|
||||||
|
Utils.deleteToTrash(osu.getFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
ErrorHandler.error("Could not delete song.", e, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the total number of parsed maps (i.e. OsuFile objects).
|
* Returns the total number of parsed maps (i.e. OsuFile objects).
|
||||||
*/
|
*/
|
||||||
|
@ -169,13 +294,13 @@ public class OsuGroupList {
|
||||||
if (node == null)
|
if (node == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
OsuGroupNode firstInserted = null;
|
expandedStartNode = expandedEndNode = null;
|
||||||
|
|
||||||
// create new nodes
|
// create new nodes
|
||||||
ArrayList<OsuFile> osuFiles = node.osuFiles;
|
ArrayList<OsuFile> osuFiles = node.osuFiles;
|
||||||
OsuGroupNode prevNode = node.prev;
|
OsuGroupNode prevNode = node.prev;
|
||||||
OsuGroupNode nextNode = node.next;
|
OsuGroupNode nextNode = node.next;
|
||||||
for (int i = 0; i < node.osuFiles.size(); i++) {
|
for (int i = 0, size = node.osuFiles.size(); i < size; i++) {
|
||||||
OsuGroupNode newNode = new OsuGroupNode(osuFiles);
|
OsuGroupNode newNode = new OsuGroupNode(osuFiles);
|
||||||
newNode.index = index;
|
newNode.index = index;
|
||||||
newNode.osuFileIndex = i;
|
newNode.osuFileIndex = i;
|
||||||
|
@ -183,7 +308,7 @@ public class OsuGroupList {
|
||||||
|
|
||||||
// unlink the group node
|
// unlink the group node
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
firstInserted = newNode;
|
expandedStartNode = newNode;
|
||||||
newNode.prev = prevNode;
|
newNode.prev = prevNode;
|
||||||
if (prevNode != null)
|
if (prevNode != null)
|
||||||
prevNode.next = newNode;
|
prevNode.next = newNode;
|
||||||
|
@ -196,9 +321,10 @@ public class OsuGroupList {
|
||||||
node.next = nextNode;
|
node.next = nextNode;
|
||||||
nextNode.prev = node;
|
nextNode.prev = node;
|
||||||
}
|
}
|
||||||
|
expandedEndNode = node;
|
||||||
|
|
||||||
expandedIndex = index;
|
expandedIndex = index;
|
||||||
return firstInserted;
|
return expandedStartNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -222,6 +348,7 @@ public class OsuGroupList {
|
||||||
eNext.prev = eCur;
|
eNext.prev = eCur;
|
||||||
|
|
||||||
expandedIndex = -1;
|
expandedIndex = -1;
|
||||||
|
expandedStartNode = expandedEndNode = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,6 +362,7 @@ public class OsuGroupList {
|
||||||
// sort the list
|
// sort the list
|
||||||
Collections.sort(nodes, SongSort.getSort().getComparator());
|
Collections.sort(nodes, SongSort.getSort().getComparator());
|
||||||
expandedIndex = -1;
|
expandedIndex = -1;
|
||||||
|
expandedStartNode = expandedEndNode = null;
|
||||||
|
|
||||||
// create links
|
// create links
|
||||||
OsuGroupNode lastNode = nodes.get(0);
|
OsuGroupNode lastNode = nodes.get(0);
|
||||||
|
|
|
@ -72,9 +72,12 @@ public class OsuParser {
|
||||||
* Invokes parser for each directory in the given array and
|
* Invokes parser for each directory in the given array and
|
||||||
* adds the OsuFiles to the existing OsuGroupList.
|
* adds the OsuFiles to the existing OsuGroupList.
|
||||||
* @param dirs the array of directories to parse
|
* @param dirs the array of directories to parse
|
||||||
* @return the last OsuGroupNode parsed
|
* @return the last OsuGroupNode parsed, or null if none
|
||||||
*/
|
*/
|
||||||
public static OsuGroupNode parseDirectories(File[] dirs) {
|
public static OsuGroupNode parseDirectories(File[] dirs) {
|
||||||
|
if (dirs == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
// progress tracking
|
// progress tracking
|
||||||
currentDirectoryIndex = 0;
|
currentDirectoryIndex = 0;
|
||||||
totalDirectories = dirs.length;
|
totalDirectories = dirs.length;
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class OszUnpacker {
|
||||||
return name.toLowerCase().endsWith(".osz");
|
return name.toLowerCase().endsWith(".osz");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (files.length < 1) {
|
if (files == null || files.length < 1) {
|
||||||
files = null;
|
files = null;
|
||||||
return new File[0];
|
return new File[0];
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import itdelatrisu.opsu.downloads.DownloadNode;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
@ -55,6 +56,8 @@ import org.newdawn.slick.state.StateBasedGame;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import org.newdawn.slick.util.ResourceLoader;
|
import org.newdawn.slick.util.ResourceLoader;
|
||||||
|
|
||||||
|
import com.sun.jna.platform.FileUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains miscellaneous utilities.
|
* Contains miscellaneous utilities.
|
||||||
*/
|
*/
|
||||||
|
@ -738,4 +741,60 @@ public class Utils {
|
||||||
}
|
}
|
||||||
return cleanName.toString();
|
return cleanName.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a file or directory. If a system trash directory is available,
|
||||||
|
* the file or directory will be moved there instead.
|
||||||
|
* @param file the file or directory to delete
|
||||||
|
* @return true if moved to trash, and false if deleted
|
||||||
|
* @throws IOException if given file does not exist
|
||||||
|
*/
|
||||||
|
public static boolean deleteToTrash(File file) throws IOException {
|
||||||
|
if (file == null)
|
||||||
|
throw new IOException("File cannot be null.");
|
||||||
|
if (!file.exists())
|
||||||
|
throw new IOException(String.format("File '%s' does not exist.", file.getAbsolutePath()));
|
||||||
|
|
||||||
|
// move to system trash, if possible
|
||||||
|
FileUtils fileUtils = FileUtils.getInstance();
|
||||||
|
if (fileUtils.hasTrash()) {
|
||||||
|
try {
|
||||||
|
fileUtils.moveToTrash(new File[] { file });
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.warn(String.format("Failed to move file '%s' to trash.", file.getAbsolutePath()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete otherwise
|
||||||
|
if (file.isDirectory())
|
||||||
|
deleteDirectory(file);
|
||||||
|
else
|
||||||
|
file.delete();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively deletes all files and folders in a directory, then
|
||||||
|
* deletes the directory itself.
|
||||||
|
* @param dir the directory to delete
|
||||||
|
*/
|
||||||
|
private static void deleteDirectory(File dir) {
|
||||||
|
if (dir == null || !dir.isDirectory())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// recursively delete contents of directory
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files != null && files.length > 0) {
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory())
|
||||||
|
deleteDirectory(file);
|
||||||
|
else
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the directory
|
||||||
|
dir.delete();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -396,6 +396,8 @@ public class SongMenu extends BasicGameState {
|
||||||
|
|
||||||
// search produced new list: re-initialize it
|
// search produced new list: re-initialize it
|
||||||
startNode = focusNode = null;
|
startNode = focusNode = null;
|
||||||
|
scoreMap = null;
|
||||||
|
focusScores = null;
|
||||||
if (OsuGroupList.get().size() > 0) {
|
if (OsuGroupList.get().size() > 0) {
|
||||||
OsuGroupList.get().init();
|
OsuGroupList.get().init();
|
||||||
if (search.getText().isEmpty()) { // cleared search
|
if (search.getText().isEmpty()) { // cleared search
|
||||||
|
@ -606,6 +608,8 @@ public class SongMenu extends BasicGameState {
|
||||||
// reset state and node references
|
// reset state and node references
|
||||||
MusicController.reset();
|
MusicController.reset();
|
||||||
startNode = focusNode = null;
|
startNode = focusNode = null;
|
||||||
|
scoreMap = null;
|
||||||
|
focusScores = null;
|
||||||
oldFocusNode = null;
|
oldFocusNode = null;
|
||||||
randomStack = new Stack<SongNode>();
|
randomStack = new Stack<SongNode>();
|
||||||
songInfo = null;
|
songInfo = null;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user