diff --git a/src/main/java/tech/minediamond/vortex/config/AppModule.java b/src/main/java/tech/minediamond/vortex/config/AppModule.java
index 3277615..c2b7f13 100644
--- a/src/main/java/tech/minediamond/vortex/config/AppModule.java
+++ b/src/main/java/tech/minediamond/vortex/config/AppModule.java
@@ -27,6 +27,7 @@
import tech.minediamond.vortex.service.appConfig.AppConfigService;
import tech.minediamond.vortex.service.autoStart.MockAutoStartService;
import tech.minediamond.vortex.service.autoStart.WindowsAutoStartService;
+import tech.minediamond.vortex.service.search.SearchService;
import tech.minediamond.vortex.service.ui.ShowStageListenerFactory;
import tech.minediamond.vortex.service.autoStart.IAutoStartService;
import tech.minediamond.vortex.service.i18n.I18nService;
@@ -36,6 +37,7 @@
import tech.minediamond.vortex.service.ui.TrayMenuService;
import tech.minediamond.vortex.service.ui.WindowAnimator;
import tech.minediamond.vortex.service.uncaughtExceptionHandle.GlobalUncaughtExceptionHandlerService;
+import tech.minediamond.vortex.ui.component.SearchResultCardFactory;
import tech.minediamond.vortex.ui.controller.EditorPanel;
import tech.minediamond.vortex.ui.controller.MainWindow;
import tech.minediamond.vortex.ui.controller.SettingPanel;
@@ -58,6 +60,7 @@ protected void configure() {
bind(EditorPanel.class);
bind(SettingPanel.class);
bind(TrayMenuService.class);
+ bind(SearchService.class);
bind(WindowAnimator.class).in(Scopes.SINGLETON);
@@ -76,6 +79,6 @@ protected void configure() {
// 告诉 Guice,这个工厂的实现是基于 ShowStageListenerFactory 接口
.build(ShowStageListenerFactory.class));
-
+ install(new FactoryModuleBuilder().build(SearchResultCardFactory.class));
}
}
diff --git a/src/main/java/tech/minediamond/vortex/model/search/EverythingResult.java b/src/main/java/tech/minediamond/vortex/model/fileData/FileData.java
similarity index 72%
rename from src/main/java/tech/minediamond/vortex/model/search/EverythingResult.java
rename to src/main/java/tech/minediamond/vortex/model/fileData/FileData.java
index 45c1a01..841a328 100644
--- a/src/main/java/tech/minediamond/vortex/model/search/EverythingResult.java
+++ b/src/main/java/tech/minediamond/vortex/model/fileData/FileData.java
@@ -17,19 +17,21 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-package tech.minediamond.vortex.model.search;
+package tech.minediamond.vortex.model.fileData;
import lombok.Getter;
import lombok.Setter;
+import lombok.ToString;
import java.util.Date;
import java.util.Objects;
@Getter
@Setter
-public class EverythingResult {
- private ResultType type;
+@ToString
+public class FileData {
+ private FileType type;
private String fileName;
private String extension;
private String fullPath;
@@ -37,11 +39,11 @@ public class EverythingResult {
private Date dateModified;
private Date dateCreated;
- public EverythingResult(){
+ public FileData(){
}
- public EverythingResult(ResultType type, String fileName, String extension, String fullPath, long size, Date dateModified, Date dateCreated) {
+ public FileData(FileType type, String fileName, String extension, String fullPath, long size, Date dateModified, Date dateCreated) {
this.type = type;
this.fileName = fileName;
this.extension = extension;
@@ -51,20 +53,19 @@ public EverythingResult(ResultType type, String fileName, String extension, Stri
this.dateCreated = dateCreated;
}
- @Override
- public String toString() {
- return "EverythingResult{" +
- "type=" + type +
- ", fileName='" + fileName + '\'' +
- ", fullPath='" + fullPath + '\'' +
- '}';
+ public String getParentPath(){
+ return switch (type){
+ case FILE-> fullPath.substring(0, fullPath.lastIndexOf('\\'));
+ case FOLDER-> fullPath;
+ };
}
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- return Objects.equals(fullPath, ((EverythingResult) o).fullPath);
+ return Objects.equals(fullPath, ((FileData) o).fullPath);
}
@Override
diff --git a/src/main/java/tech/minediamond/vortex/model/search/ResultType.java b/src/main/java/tech/minediamond/vortex/model/fileData/FileType.java
similarity index 91%
rename from src/main/java/tech/minediamond/vortex/model/search/ResultType.java
rename to src/main/java/tech/minediamond/vortex/model/fileData/FileType.java
index 9d6eff6..bcf3cc0 100644
--- a/src/main/java/tech/minediamond/vortex/model/search/ResultType.java
+++ b/src/main/java/tech/minediamond/vortex/model/fileData/FileType.java
@@ -17,9 +17,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-package tech.minediamond.vortex.model.search;
+package tech.minediamond.vortex.model.fileData;
-public enum ResultType {
+public enum FileType {
FILE,
FOLDER
}
diff --git a/src/main/java/tech/minediamond/vortex/model/ui/ContentPanel.java b/src/main/java/tech/minediamond/vortex/model/ui/ContentPanel.java
index deff287..bad95ef 100644
--- a/src/main/java/tech/minediamond/vortex/model/ui/ContentPanel.java
+++ b/src/main/java/tech/minediamond/vortex/model/ui/ContentPanel.java
@@ -20,8 +20,9 @@
package tech.minediamond.vortex.model.ui;
public enum ContentPanel {
- EDITORPANEL("editorPanel.fxml"),
- SETTINGPANEL("settingPanel.fxml");
+ EDITOR_PANEL("editorPanel.fxml"),
+ SETTING_PANEL("settingPanel.fxml"),
+ SEARCH_PANEL("searchPanel.fxml");
private final String fileName;
diff --git a/src/main/java/tech/minediamond/vortex/service/search/Everything3.java b/src/main/java/tech/minediamond/vortex/service/search/Everything3.java
index 2fe1fe4..58483e2 100644
--- a/src/main/java/tech/minediamond/vortex/service/search/Everything3.java
+++ b/src/main/java/tech/minediamond/vortex/service/search/Everything3.java
@@ -41,7 +41,8 @@ public interface Everything3 extends StdCallLibrary {
enum PropertyType {
FILE_NAME(0),
SIZE(2),
- FULL_PATH(240);
+ FULL_PATH(240),
+ IS_FOLDER(269);
final WinDef.DWORD ID;
@@ -166,6 +167,16 @@ class EverythingResultList extends PointerType {
*/
void Everything3_GetResultPropertyTextW(EverythingResultList resultList, WinDef.DWORD result_index, WinDef.DWORD propertyID, char[] buffer, WinDef.DWORD filename_size_in_wchars);
+ /**
+ * 根据属性值获取结果的特定属性
+ *
+ * @param resultList 结果列表句柄。
+ * @param result_index 结果的从零开始的索引。
+ * @param propertyID 需要获取的属性的属性值
+ * @return 返回的属性信息
+ */
+ byte Everything3_GetResultPropertyBYTE(EverythingResultList resultList, WinDef.DWORD result_index, WinDef.DWORD propertyID);
+
/**
* 使用给定的客户端和搜索状态执行搜索。
diff --git a/src/main/java/tech/minediamond/vortex/service/search/EverythingQueryBuilder.java b/src/main/java/tech/minediamond/vortex/service/search/EverythingQueryBuilder.java
index ff87f36..6320174 100644
--- a/src/main/java/tech/minediamond/vortex/service/search/EverythingQueryBuilder.java
+++ b/src/main/java/tech/minediamond/vortex/service/search/EverythingQueryBuilder.java
@@ -20,7 +20,7 @@
package tech.minediamond.vortex.service.search;
import tech.minediamond.vortex.model.search.EverythingQuery;
-import tech.minediamond.vortex.model.search.EverythingResult;
+import tech.minediamond.vortex.model.fileData.FileData;
import tech.minediamond.vortex.model.search.SearchMode;
import java.nio.file.Path;
@@ -38,7 +38,7 @@
*
{@link #mode(SearchMode)} - 设置搜索模式(文件/文件夹/全部)
*
*
- * 构建完成后,通过{@code query()}发起请求,并返回一个{@code List}
+ * 构建完成后,通过{@code query()}发起请求,并返回一个{@code List}
*
* @see EverythingService
*/
@@ -106,7 +106,7 @@ private EverythingQuery build() {
*
* @return 搜索结果列表
*/
- public List query() {
+ public List query() {
if (query == null || query.trim().isEmpty()) {
return Collections.emptyList();
}
diff --git a/src/main/java/tech/minediamond/vortex/service/search/EverythingService.java b/src/main/java/tech/minediamond/vortex/service/search/EverythingService.java
index 8a5e55b..94478f4 100644
--- a/src/main/java/tech/minediamond/vortex/service/search/EverythingService.java
+++ b/src/main/java/tech/minediamond/vortex/service/search/EverythingService.java
@@ -25,8 +25,9 @@
import com.sun.jna.WString;
import com.sun.jna.platform.win32.WinDef;
import lombok.extern.slf4j.Slf4j;
+import tech.minediamond.vortex.model.fileData.FileType;
import tech.minediamond.vortex.model.search.EverythingQuery;
-import tech.minediamond.vortex.model.search.EverythingResult;
+import tech.minediamond.vortex.model.fileData.FileData;
import tech.minediamond.vortex.model.search.SearchMode;
import java.io.IOException;
@@ -49,7 +50,7 @@
* 使用示例:
*
* EverythingService service = injector.getInstance(EverythingServiceTest.class);
- * List<EverythingResult> results = service.QueryBuilder()
+ * List<FileData> results = service.QueryBuilder()
* .searchFor("document")
* .inFolders(List.of(Path.of("C:/Users")))
* .mode(SearchMode.FILES_ONLY)
@@ -57,7 +58,7 @@
*
*
* @see EverythingQueryBuilder
- * @see EverythingResult
+ * @see FileData
*/
@Singleton
@Slf4j
@@ -150,7 +151,7 @@ public Everything3.EverythingClient LinkEverythingInstance() {
return client;
}
- public List query(EverythingQuery query) {
+ public List query(EverythingQuery query) {
// 防御性检查
if (client == null) {
@@ -165,12 +166,12 @@ public List query(EverythingQuery query) {
Everything3.EverythingSearchState searchState = null;
Everything3.EverythingResultList resultList = null;
- List results = new ArrayList<>();
+ List results = new ArrayList<>();
try {
// 创建和配置搜索条件
searchState = lib.Everything3_CreateSearchState();
if (searchState == null) {
- log.error("创建搜索失败。");
+ log.error("无法执行查询:创建搜索失败。");
}
// 设置搜索关键字
String finalQueryString;
@@ -180,6 +181,7 @@ public List query(EverythingQuery query) {
lib.Everything3_AddSearchPropertyRequest(searchState, Everything3.PropertyType.FULL_PATH.getID());
lib.Everything3_AddSearchPropertyRequest(searchState, Everything3.PropertyType.SIZE.getID());
lib.Everything3_AddSearchPropertyRequest(searchState, Everything3.PropertyType.FILE_NAME.getID());
+ lib.Everything3_AddSearchPropertyRequest(searchState, Everything3.PropertyType.IS_FOLDER.getID());
//生成搜索词字符串
String queryKeywords = "\"" + query.query() + "\"";
@@ -220,24 +222,35 @@ public List query(EverythingQuery query) {
char[] buffer = new char[MAX_PATH];
+ WinDef.DWORD resultListindex = new WinDef.DWORD();
for (int i = 0; i < numResults.intValue(); i++) {
- EverythingResult everythingResult = new EverythingResult();
+ FileData fileData = new FileData();
+ resultListindex.setValue(i);
//获取搜索结果的完整路径
- lib.Everything3_GetResultPropertyTextW(resultList, new WinDef.DWORD(i), Everything3.PropertyType.FULL_PATH.getID(), buffer, new WinDef.DWORD(MAX_PATH));
+ lib.Everything3_GetResultPropertyTextW(resultList, resultListindex, Everything3.PropertyType.FULL_PATH.getID(), buffer, new WinDef.DWORD(MAX_PATH));
String pathname = Native.toString(buffer);
- everythingResult.setFullPath(pathname);
+ fileData.setFullPath(pathname);
//获取搜索结果的名称
- lib.Everything3_GetResultPropertyTextW(resultList, new WinDef.DWORD(i), Everything3.PropertyType.FILE_NAME.getID(), buffer, new WinDef.DWORD(MAX_PATH));
+ lib.Everything3_GetResultPropertyTextW(resultList, resultListindex, Everything3.PropertyType.FILE_NAME.getID(), buffer, new WinDef.DWORD(MAX_PATH));
String filename = Native.toString(buffer);
- everythingResult.setFileName(filename);
+ fileData.setFileName(filename);
//获取搜索结果的大小(单位:Byte)
//这里直接将返回的无符号int64转换为long,但是考虑到无符号int64达到最大位需要文件8EB以上的大小,因此直接赋值问题不大
- long size = lib.Everything3_GetResultSize(resultList, new WinDef.DWORD(i));
- everythingResult.setSize(size);
+ long size = lib.Everything3_GetResultSize(resultList, resultListindex);
+ fileData.setSize(size);
- results.add(everythingResult);
+ //获取文件的类型
+ byte type = lib.Everything3_GetResultPropertyBYTE(resultList, resultListindex, Everything3.PropertyType.IS_FOLDER.getID());
+ int intType = type & 0xFF;
+ if (intType != 0) {
+ fileData.setType(FileType.FOLDER);
+ } else {
+ fileData.setType(FileType.FILE);
+ }
+
+ results.add(fileData);
}
} finally {
if (resultList != null) {
@@ -258,14 +271,14 @@ private String buildPathQueryPart(EverythingQuery query) {
.map(Path::toString)
.collect(Collectors.joining("|"));
String pathQueryPart = "ancestor:" + body;
- log.debug("pathQueryPart: {}",pathQueryPart);
+ log.debug("搜索路径关键词: {}",pathQueryPart);
return pathQueryPart;
}
//构建搜索描述部分字符串
private String buildSearchModeQueryPart(EverythingQuery query) {
SearchMode searchMode = query.searchMode().orElse(SearchMode.ALL);
- log.debug("searchModeQueryPart: {}",searchMode.getQueryPrefix());
+ log.debug("searchMode关键词: {}",searchMode.getQueryPrefix());
return searchMode.getQueryPrefix();
}
diff --git a/src/main/java/tech/minediamond/vortex/service/search/SearchService.java b/src/main/java/tech/minediamond/vortex/service/search/SearchService.java
new file mode 100644
index 0000000..3e4dd76
--- /dev/null
+++ b/src/main/java/tech/minediamond/vortex/service/search/SearchService.java
@@ -0,0 +1,114 @@
+/*
+ * Vortex
+ * Copyright (C) 2025 Mine-diamond
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package tech.minediamond.vortex.service.search;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
+import javafx.concurrent.Service;
+import javafx.concurrent.Task;
+import lombok.extern.slf4j.Slf4j;
+import tech.minediamond.vortex.model.fileData.FileData;
+import tech.minediamond.vortex.model.search.SearchMode;
+import tech.minediamond.vortex.service.i18n.I18nService;
+import tech.minediamond.vortex.ui.component.ComponentList;
+import tech.minediamond.vortex.ui.component.SearchResultCard;
+import tech.minediamond.vortex.ui.component.SearchResultCardFactory;
+import tech.minediamond.vortex.util.ClipboardUtil;
+import tech.minediamond.vortex.util.OpenResourceUtil;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+@Slf4j
+public class SearchService extends Service {
+
+ private final String NAME = "Search Thread";
+
+ private final EverythingService everythingService;
+ private final I18nService i18n;
+ private final Injector injector;
+ private final StringProperty keyword = new SimpleStringProperty();
+
+ private final ThreadFactory searchThreadFactory;
+ private final ExecutorService executor;
+
+ @Inject
+ public SearchService(EverythingService everythingService, I18nService i18n, Injector injector) {
+ this.everythingService = everythingService;
+ this.i18n = i18n;
+ this.injector = injector;
+
+ searchThreadFactory = r -> {
+ Thread t = new Thread(r, NAME);
+ t.setDaemon(true);
+ return t;
+ };
+ executor = Executors.newSingleThreadExecutor(searchThreadFactory);
+ setExecutor(executor);
+
+ }
+
+ public String getKeyword() {
+ return keyword.get();
+ }
+
+ public void search(String keyword) {
+ this.keyword.set(keyword);
+ restart();
+ }
+
+ @Override
+ protected Task createTask() {
+ return new Task() {
+
+ @Override
+ protected ComponentList call() throws Exception {
+ List results = everythingService.QueryBuilder()
+ .mode(SearchMode.ALL)
+ .searchFor(keyword.get())
+ .query();
+
+ ComponentList componentList = new ComponentList();
+
+ if (results.isEmpty()) {
+ updateProgress(0, 1);
+ return null;
+ }
+
+ for (FileData result : results) {
+ SearchResultCard card = injector.getInstance(SearchResultCardFactory.class).create(result);
+ card.setOnOpen(OpenResourceUtil::OpenFile);
+ card.setOnRevealInFolder(OpenResourceUtil::OpenFileInFolder);
+ card.setOnCopy(fileData -> ClipboardUtil.copyToClipboard(fileData.getFullPath()));
+ card.setOnOpenPathInTerminal(OpenResourceUtil::OpenPathInTerminal);
+ componentList.addNode(card);
+ }
+
+ log.info("搜索成功");
+ return componentList;
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/tech/minediamond/vortex/ui/component/SearchResultCard.java b/src/main/java/tech/minediamond/vortex/ui/component/SearchResultCard.java
new file mode 100644
index 0000000..a5d3474
--- /dev/null
+++ b/src/main/java/tech/minediamond/vortex/ui/component/SearchResultCard.java
@@ -0,0 +1,196 @@
+/*
+ * Vortex
+ * Copyright (C) 2025 Mine-diamond
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package tech.minediamond.vortex.ui.component;
+
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.scene.control.Button;
+import javafx.scene.control.Control;
+import javafx.scene.control.Label;
+import javafx.scene.control.SkinBase;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+import lombok.Getter;
+import org.kordamp.ikonli.fluentui.FluentUiRegularAL;
+import org.kordamp.ikonli.fluentui.FluentUiRegularMZ;
+import org.kordamp.ikonli.javafx.FontIcon;
+import tech.minediamond.vortex.model.fileData.FileData;
+import tech.minediamond.vortex.service.i18n.I18nService;
+
+import java.util.function.Consumer;
+
+public class SearchResultCard extends Control {
+
+ private final ObjectProperty> onOpen = new SimpleObjectProperty<>();
+ private final ObjectProperty> onRevealInFolder = new SimpleObjectProperty<>();
+ private final ObjectProperty> onCopy = new SimpleObjectProperty<>();
+ private final ObjectProperty> onOpenPathInTerminal = new SimpleObjectProperty<>();
+
+ private final I18nService i18n;
+
+ @Getter
+ private final FileData result;
+
+ @Inject
+ public SearchResultCard(@Assisted FileData result, I18nService i18n) {
+ this.result = result;
+ this.i18n = i18n;
+ }
+
+ @Override
+ protected Skin createDefaultSkin() {
+ return new Skin(this);
+ }
+
+ public Consumer getOnOpen() {
+ return onOpen.get();
+ }
+
+ public void setOnOpen(Consumer action) {
+ onOpen.set(action);
+ }
+
+ public ObjectProperty> onOpenProperty() {
+ return onOpen;
+ }
+
+ public Consumer getOnRevealInFolder() {
+ return onRevealInFolder.get();
+ }
+
+ public void setOnRevealInFolder(Consumer action) {
+ onRevealInFolder.set(action);
+ }
+
+ public ObjectProperty> onRevealInFolderProperty() {
+ return onRevealInFolder;
+ }
+
+ public Consumer getOnCopy() {
+ return onCopy.get();
+ }
+
+ public void setOnCopy(Consumer action) {
+ onCopy.set(action);
+ }
+
+ public ObjectProperty> onCopyProperty() {
+ return onCopy;
+ }
+
+ public Consumer getOnOpenPathInTerminal() {
+ return onOpenPathInTerminal.get();
+ }
+
+ public void setOnOpenPathInTerminal(Consumer action) {
+ onOpenPathInTerminal.set(action);
+ }
+
+ public ObjectProperty> onOpenPathInTerminalProperty() {
+ return onOpenPathInTerminal;
+ }
+
+ public void open() {
+ Consumer c = getOnOpen();
+ if (c != null) c.accept(result);
+ }
+
+ public void revealInFolder() {
+ Consumer c = getOnRevealInFolder();
+ if (c != null) c.accept(result);
+ }
+
+ public void copy() {
+ Consumer c = getOnCopy();
+ if (c != null) c.accept(result);
+ }
+
+ public void openPathInTerminal() {
+ Consumer c = getOnOpenPathInTerminal();
+ if (c != null) c.accept(result);
+ }
+
+ private final class Skin extends SkinBase {
+
+ private final FontIcon openInFolderIcon = new FontIcon(FluentUiRegularAL.FOLDER_24);
+ private final FontIcon openIcon = new FontIcon(FluentUiRegularMZ.OPEN_24);
+ private final FontIcon copyPathIcon = new FontIcon(FluentUiRegularAL.COPY_24);
+ private final FontIcon terminalIcon = new FontIcon(FluentUiRegularMZ.WINDOW_HORIZONTAL_20);
+
+ HBox hBox = new HBox();
+ VBox vbox = new VBox();
+
+ /**
+ * Constructor for all SkinBase instances.
+ *
+ * @param control The control for which this Skin should attach to.
+ */
+ protected Skin(SearchResultCard control) {
+ super(control);
+
+ hBox.getStyleClass().add("search-result-card");
+
+ Label fileNameLabel = new Label(control.result.getFileName());
+ Label filePathLabel = new Label(control.result.getFullPath());
+ fileNameLabel.getStyleClass().add("search-result-name-label");
+ filePathLabel.getStyleClass().add("search-result-file-path");
+
+ Button openBtn = new Button();
+ openBtn.setGraphic(openIcon);
+ openBtn.visibleProperty().bind(hBox.hoverProperty());
+ openBtn.managedProperty().bind(hBox.hoverProperty());
+ openBtn.setOnAction(e -> getSkinnable().open());
+ SimpleHoverTooltip.textProperty(openBtn).set(i18n.t("file.open.tip"));
+
+ Button openInFolderBtn = new Button();
+ openInFolderBtn.setGraphic(openInFolderIcon);
+ openInFolderBtn.visibleProperty().bind(hBox.hoverProperty());
+ openInFolderBtn.managedProperty().bind(hBox.hoverProperty());
+ openInFolderBtn.setOnAction(e -> getSkinnable().revealInFolder());
+ SimpleHoverTooltip.textProperty(openInFolderBtn).set(i18n.t("file.openInFolder.tip"));
+
+ Button copyPathBtn = new Button();
+ copyPathBtn.setGraphic(copyPathIcon);
+ copyPathBtn.visibleProperty().bind(hBox.hoverProperty());
+ copyPathBtn.managedProperty().bind(hBox.hoverProperty());
+ copyPathBtn.setOnAction(e -> getSkinnable().copy());
+ SimpleHoverTooltip.textProperty(copyPathBtn).set(i18n.t("file.copyPath.tip"));
+
+ Button openPathInTerminal = new Button();
+ openPathInTerminal.setGraphic(terminalIcon);
+ openPathInTerminal.visibleProperty().bind(hBox.hoverProperty());
+ openPathInTerminal.managedProperty().bind(hBox.hoverProperty());
+ openPathInTerminal.setOnAction(e -> getSkinnable().openPathInTerminal());
+ SimpleHoverTooltip.textProperty(openPathInTerminal).set(i18n.t("file.openPathInTerminal.tip"));
+
+ Region region = new Region();
+ HBox.setHgrow(region, Priority.ALWAYS);
+
+ vbox.getChildren().addAll(fileNameLabel, filePathLabel);
+ hBox.getChildren().addAll(vbox, region, openBtn, openInFolderBtn, copyPathBtn, openPathInTerminal);
+ getChildren().add(hBox);
+ }
+ }
+
+}
diff --git a/src/main/java/tech/minediamond/vortex/ui/component/SearchResultCardFactory.java b/src/main/java/tech/minediamond/vortex/ui/component/SearchResultCardFactory.java
new file mode 100644
index 0000000..89812ba
--- /dev/null
+++ b/src/main/java/tech/minediamond/vortex/ui/component/SearchResultCardFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Vortex
+ * Copyright (C) 2025 Mine-diamond
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package tech.minediamond.vortex.ui.component;
+
+import tech.minediamond.vortex.model.fileData.FileData;
+
+public interface SearchResultCardFactory {
+
+ SearchResultCard create(FileData result);
+
+}
diff --git a/src/main/java/tech/minediamond/vortex/ui/controller/MainWindow.java b/src/main/java/tech/minediamond/vortex/ui/controller/MainWindow.java
index 40e98e0..ecaee1d 100644
--- a/src/main/java/tech/minediamond/vortex/ui/controller/MainWindow.java
+++ b/src/main/java/tech/minediamond/vortex/ui/controller/MainWindow.java
@@ -25,11 +25,14 @@
import com.google.inject.Injector;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.Button;
+import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.Image;
@@ -47,19 +50,14 @@
import tech.minediamond.vortex.model.appConfig.AppConfig;
import tech.minediamond.vortex.model.ui.ContentPanel;
import tech.minediamond.vortex.model.ui.Theme;
-import tech.minediamond.vortex.service.ui.ShowStageListenerFactory;
import tech.minediamond.vortex.service.i18n.I18nService;
-import tech.minediamond.vortex.service.ui.AutoOperateService;
-import tech.minediamond.vortex.service.ui.ShowStageListener;
-import tech.minediamond.vortex.service.ui.StageProvider;
-import tech.minediamond.vortex.service.ui.WindowAnimator;
+import tech.minediamond.vortex.service.ui.*;
import tech.minediamond.vortex.ui.component.SimpleHoverTooltip;
import tech.minediamond.vortex.util.BindingUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
-import java.util.Optional;
import static tech.minediamond.vortex.model.ui.Theme.*;
@@ -71,24 +69,30 @@ public class MainWindow {
private final I18nService i18n;
private final AutoOperateService autoOperateService;
- private static ContentPanel currentContentPanel;
-
@FXML
private AnchorPane mainWindow;
@FXML
private AnchorPane tabWindow;
@FXML
+ private TextField searchField;
+ @FXML
private ToggleButton pinBtn;
@FXML
private ToggleGroup mainToggleGroup;
@FXML
private ToggleButton quickEditBtn;
@FXML
+ private ToggleButton searchBtn;
+ @FXML
+ private ToggleButton settingBtn;
+ @FXML
private Button themeSwitchBtn;
@FXML
private Button hideWindowBtn;
//缓存已经加载的视图
private final Map viewCache = new HashMap<>();
+ private final ObjectProperty currentContentPanelProperty = new SimpleObjectProperty<>(ContentPanel.EDITOR_PANEL);
+ private SearchPanel searchPanel;
private double xOffset = 0;
private double yOffset = 0;
@@ -122,7 +126,7 @@ public void initialize() {
handleDragWindow();
initUIComponent();
- loadOrGetView(ContentPanel.EDITORPANEL);
+ loadOrGetView(currentContentPanelProperty.get());
mainToggleGroup.selectToggle(quickEditBtn);
}
@@ -183,8 +187,27 @@ public void initUIComponent() {
mainToggleGroup.selectToggle(oldValue);
}
});
+
+ currentContentPanelProperty.addListener((observable, oldValue, newValue) -> {
+ loadOrGetView(newValue);
+ switch (newValue) {
+ case EDITOR_PANEL -> mainToggleGroup.selectToggle(quickEditBtn);
+ case SETTING_PANEL -> mainToggleGroup.selectToggle(settingBtn);
+ case SEARCH_PANEL -> mainToggleGroup.selectToggle(searchBtn);
+ }
+ });
+
+ searchField.textProperty().addListener((observable, oldValue, newValue) -> {
+ if (newValue != null && !newValue.isEmpty()) {
+ currentContentPanelProperty.set(ContentPanel.SEARCH_PANEL);
+ searchPanel.search(newValue);
+ } else if (newValue.isEmpty()) {
+ searchPanel.searchClear();
+ }
+ });
}
+
/**
* 设置主窗口的属性
*/
@@ -246,10 +269,6 @@ public void setupWindowListeners() {
* @param fxmlFileName 文件名
*/
private void loadOrGetView(ContentPanel fxmlFileName) {
- if (fxmlFileName == currentContentPanel) {
- log.info("原页面:{},新页面:{},页面一致", fxmlFileName.getFileName(), currentContentPanel.getFileName());
- return;
- }
String fileName = fxmlFileName.getFileName();
Parent view = viewCache.get(fileName);
@@ -260,31 +279,36 @@ private void loadOrGetView(ContentPanel fxmlFileName) {
loader.setResources(injector.getInstance(I18nService.class).getResourceBundle());
view = loader.load();
viewCache.put(fileName, view); // 加载后放入缓存
+ if (fxmlFileName == ContentPanel.SEARCH_PANEL) {
+ searchPanel = loader.getController();
+ }
// 让新视图充满 tabWindow
AnchorPane.setTopAnchor(view, 0.0);
AnchorPane.setBottomAnchor(view, 0.0);
AnchorPane.setLeftAnchor(view, 0.0);
AnchorPane.setRightAnchor(view, 0.0);
- log.info("原页面:{},新页面:{},从文件加载新页面", Optional.ofNullable(currentContentPanel).map(ContentPanel::getFileName).orElse("无"), fxmlFileName.getFileName());
+ log.info("加载新页面:{},从文件加载新页面", fxmlFileName.getFileName());
} catch (IOException e) {
log.error("加载 {} 页面出现错误: ", fileName, e);
return;
}
} else {
- log.info("原页面:{},新页面:{},从缓存加载新页面", Optional.ofNullable(currentContentPanel).map(ContentPanel::getFileName).orElse("无"), fxmlFileName.getFileName());
+ log.info("加载新页面:{},从缓存加载新页面", fxmlFileName.getFileName());
}
- currentContentPanel = fxmlFileName;
//更新tabWindow
tabWindow.getChildren().setAll(view);
}
public void showEditorPanel(ActionEvent actionEvent) {
- loadOrGetView(ContentPanel.EDITORPANEL);
+ currentContentPanelProperty.set(ContentPanel.EDITOR_PANEL);
}
public void showSettingPanel(ActionEvent actionEvent) {
- loadOrGetView(ContentPanel.SETTINGPANEL);
+ currentContentPanelProperty.set(ContentPanel.SETTING_PANEL);
}
+ public void showSearchPanel(ActionEvent actionEvent) {
+ currentContentPanelProperty.set(ContentPanel.SEARCH_PANEL);
+ }
}
diff --git a/src/main/java/tech/minediamond/vortex/ui/controller/SearchPanel.java b/src/main/java/tech/minediamond/vortex/ui/controller/SearchPanel.java
new file mode 100644
index 0000000..9f0a948
--- /dev/null
+++ b/src/main/java/tech/minediamond/vortex/ui/controller/SearchPanel.java
@@ -0,0 +1,114 @@
+/*
+ * Vortex
+ * Copyright (C) 2025 Mine-diamond
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package tech.minediamond.vortex.ui.controller;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import javafx.animation.PauseTransition;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.fxml.FXML;
+import javafx.geometry.Pos;
+import javafx.scene.control.Label;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.layout.HBox;
+import javafx.util.Duration;
+import lombok.extern.slf4j.Slf4j;
+import tech.minediamond.vortex.service.i18n.I18nService;
+import tech.minediamond.vortex.service.search.SearchService;
+
+@Singleton
+@Slf4j
+public class SearchPanel {
+
+ @FXML
+ private ScrollPane scrollPane;
+
+ private final PauseTransition debounce = new PauseTransition(Duration.millis(300));
+ private String keyword;
+
+ private final SearchService searchService;
+ private final I18nService i18n;
+
+ ObjectProperty searchStatusProperty = new SimpleObjectProperty<>();
+ HBox searchTiphbox = new HBox();
+ HBox searchNotFoundTiphbox = new HBox();
+
+ enum SearchStatus {
+ SEARCHING, PENDING,NOT_FOUND
+ }
+
+ @Inject
+ public SearchPanel(SearchService searchService, I18nService i18n) {
+ this.searchService = searchService;
+ this.i18n = i18n;
+
+ debounce.setOnFinished(event -> {
+ log.info("开始搜索");
+ searchService.search(keyword);
+ });
+
+ }
+
+ public void initialize() {
+ scrollPane.contentProperty().bind(searchService.valueProperty());
+
+ Label searchtipLabel = new Label(i18n.t("search.pending.text"));
+ searchTiphbox.getChildren().add(searchtipLabel);
+ searchTiphbox.setAlignment(Pos.CENTER);
+
+ Label searchNotFoundTipLabel = new Label(i18n.t("search.result.notFound.text"));
+ searchNotFoundTiphbox.getChildren().add(searchNotFoundTipLabel);
+ searchNotFoundTiphbox.setAlignment(Pos.CENTER);
+
+ searchStatusProperty.addListener((observable, oldValue, newValue) -> {//监控不同的状态展示不同的界面
+ switch (newValue) {
+ case PENDING -> {
+ scrollPane.contentProperty().unbind();
+ scrollPane.contentProperty().set(searchTiphbox);
+ }
+ case NOT_FOUND -> {
+ scrollPane.contentProperty().unbind();
+ scrollPane.contentProperty().set(searchNotFoundTiphbox);
+ }
+ case SEARCHING -> {scrollPane.contentProperty().bind(searchService.valueProperty());}
+ }
+ });
+ searchStatusProperty.set(SearchStatus.PENDING);
+
+ searchService.progressProperty().addListener((observable, oldValue, newValue) -> {
+ if (newValue.equals(0.0)) {
+ searchStatusProperty.set(SearchStatus.NOT_FOUND);
+ }
+ });
+ }
+
+ public void search(String keyword) {
+ log.debug("即将搜索");
+ searchStatusProperty.set(SearchStatus.SEARCHING);
+ this.keyword = keyword;
+ debounce.playFromStart();
+ }
+
+ public void searchClear(){
+ searchStatusProperty.set(SearchStatus.PENDING);
+ }
+
+}
diff --git a/src/main/java/tech/minediamond/vortex/util/ClipboardUtil.java b/src/main/java/tech/minediamond/vortex/util/ClipboardUtil.java
new file mode 100644
index 0000000..6c80286
--- /dev/null
+++ b/src/main/java/tech/minediamond/vortex/util/ClipboardUtil.java
@@ -0,0 +1,54 @@
+/*
+ * Vortex
+ * Copyright (C) 2025 Mine-diamond
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package tech.minediamond.vortex.util;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+
+@Slf4j
+public class ClipboardUtil {
+ /**
+ * 将指定的字符串复制到系统剪贴板。
+ *
+ * @param text 要复制的字符串。
+ */
+ public static void copyToClipboard(String text) {
+ try {
+ // 1. 获取系统剪贴板
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+
+ // 2. 创建一个 StringSelection 对象,它封装了要传输的字符串
+ StringSelection stringSelection = new StringSelection(text);
+
+ // 3. 将 StringSelection 对象放入剪贴板
+ clipboard.setContents(stringSelection, null);
+
+ log.info("成功将内容复制到剪贴板: \"{}\"", text);
+
+ } catch (HeadlessException e) {
+ log.error("无法访问剪贴板。", e);
+ } catch (Exception e) {
+ log.error("复制到剪贴板时发生错误。", e);
+ }
+ }
+}
diff --git a/src/main/java/tech/minediamond/vortex/util/OpenResourceUtil.java b/src/main/java/tech/minediamond/vortex/util/OpenResourceUtil.java
index ab9c958..018820b 100644
--- a/src/main/java/tech/minediamond/vortex/util/OpenResourceUtil.java
+++ b/src/main/java/tech/minediamond/vortex/util/OpenResourceUtil.java
@@ -20,7 +20,7 @@
package tech.minediamond.vortex.util;
import lombok.extern.slf4j.Slf4j;
-import tech.minediamond.vortex.model.search.EverythingResult;
+import tech.minediamond.vortex.model.fileData.FileData;
import java.awt.*;
import java.io.File;
@@ -33,7 +33,7 @@
public class OpenResourceUtil {
private static final Desktop desktop = Desktop.getDesktop();;
- public static boolean OpenFile(EverythingResult result) {
+ public static boolean OpenFile(FileData result) {
if (desktop.isSupported(Desktop.Action.OPEN)) {
try {
desktop.open(new File(result.getFullPath()));
@@ -46,4 +46,31 @@ public static boolean OpenFile(EverythingResult result) {
}
return false;
}
+
+ public static boolean OpenFileInFolder(FileData result) {
+
+ ProcessBuilder pb = new ProcessBuilder("explorer","/select,"+"\""+result.getFullPath()+"\"");
+ pb.redirectErrorStream(true);
+ pb.redirectOutput(ProcessBuilder.Redirect.DISCARD);
+ try {
+ pb.start();
+ return true;
+ } catch (IOException e) {
+ log.error("打开文件 {} 出现错误,文件路径:{}",result.getFileName(),result.getFullPath(),e);
+ }
+ return false;
+ }
+
+ public static boolean OpenPathInTerminal(FileData result) {
+ ProcessBuilder pb = new ProcessBuilder("wt.exe", "-d", result.getParentPath());
+ pb.redirectErrorStream(true);
+ pb.redirectOutput(ProcessBuilder.Redirect.DISCARD);
+ try {
+ pb.start();
+ return true;
+ } catch (IOException e) {
+ log.error("在控制台打开文件 {} 出现错误,文件路径:{}",result.getFileName(),result.getFullPath(),e);
+ }
+ return true;
+ }
}
diff --git a/src/main/resources/lang/I18N.properties b/src/main/resources/lang/I18N.properties
index 7d20700..2322c21 100644
--- a/src/main/resources/lang/I18N.properties
+++ b/src/main/resources/lang/I18N.properties
@@ -36,9 +36,16 @@ window.unpin=unpin
mainWindow.tab.search=search
mainWindow.tab.quickEdit=quick edit
mainWindow.tab.setting=setting
-search.text=search box
+search.promptText=search box
setting.startOnBoot.label=start on boot
alert.exit.title=error
alert.exit.headText=System not supported
-alert.exit.contentText=Vortex only supports running on Windows systems\nIt does not support running on Linux, Mac, or other\nsystems
\ No newline at end of file
+alert.exit.contentText=Vortex only supports running on Windows systems\nIt does not support running on Linux, Mac, or other\nsystems
+search.pending.text=Type text to search
+search.result.notFound.text=No results found, try searching with a different keyword
+
+file.open.tip=open
+file.openInFolder.tip=show in Folder
+file.copyPath.tip=copy File Path
+file.openPathInTerminal.tip=open Path in Console
\ No newline at end of file
diff --git a/src/main/resources/lang/I18N_en.properties b/src/main/resources/lang/I18N_en.properties
index b87717e..447587d 100644
--- a/src/main/resources/lang/I18N_en.properties
+++ b/src/main/resources/lang/I18N_en.properties
@@ -37,8 +37,14 @@ window.unpin=unpin
mainWindow.tab.search=search
mainWindow.tab.quickEdit=quick edit
mainWindow.tab.setting=setting
-search.text=search box
+search.promptText=search box
setting.startOnBoot.label=start on boot
alert.exit.title=error
alert.exit.headText=System not supported
-alert.exit.contentText=Vortex only supports running on Windows systems\nIt does not support running on Linux, Mac, or other\nsystems
\ No newline at end of file
+alert.exit.contentText=Vortex only supports running on Windows systems\nIt does not support running on Linux, Mac, or other\nsystems
+search.pending.text=Type text to search
+search.result.notFound.text=No results found, try searching with a different keyword
+file.open.tip=open
+file.openInFolder.tip=show in Folder
+file.copyPath.tip=copy File Path
+file.openPathInTerminal.tip=open Path in Console
\ No newline at end of file
diff --git a/src/main/resources/lang/I18N_zh_CN.properties b/src/main/resources/lang/I18N_zh_CN.properties
index 18ea0bb..dda7394 100644
--- a/src/main/resources/lang/I18N_zh_CN.properties
+++ b/src/main/resources/lang/I18N_zh_CN.properties
@@ -37,8 +37,14 @@ window.unpin=\u672A\u56FA\u5B9A
mainWindow.tab.search=\u641C\u7D22
mainWindow.tab.quickEdit=\u5FEB\u901F\u7F16\u8F91
mainWindow.tab.setting=\u8BBE\u7F6E
-search.text=\u641C\u7D22\u6846
+search.promptText=\u641C\u7D22\u6846
setting.startOnBoot.label=\u5F00\u673A\u81EA\u542F\u52A8
alert.exit.title=\u9519\u8BEF
alert.exit.headText=\u7CFB\u7EDF\u4E0D\u652F\u6301
-alert.exit.contentText=Vortex \u4EC5\u652F\u6301\u5728 Windows \u7CFB\u7EDF\u4E0A\u8FD0\u884C\n\u4E0D\u652F\u6301\u5728 Linux\u3001Mac \u6216\u5176\u4ED6\u7CFB\u7EDF\u4E0A\u8FD0\u884C
\ No newline at end of file
+alert.exit.contentText=Vortex \u4EC5\u652F\u6301\u5728 Windows \u7CFB\u7EDF\u4E0A\u8FD0\u884C\n\u4E0D\u652F\u6301\u5728 Linux\u3001Mac \u6216\u5176\u4ED6\u7CFB\u7EDF\u4E0A\u8FD0\u884C
+search.pending.text=\u952E\u5165\u6587\u672C\u4EE5\u641C\u7D22
+search.result.notFound.text=\u6CA1\u627E\u5230\u4EFB\u4F55\u7ED3\u679C\uFF0C\u5C1D\u8BD5\u6362\u4E00\u4E2A\u5173\u952E\u8BCD\u641C\u7D22
+file.open.tip=\u6253\u5F00
+file.openInFolder.tip=\u5728\u6587\u4EF6\u5939\u4E2D\u663E\u793A
+file.copyPath.tip=\u590D\u5236\u6587\u4EF6\u8DEF\u5F84
+file.openPathInTerminal.tip=\u5728\u63A7\u5236\u53F0\u4E2D\u6253\u5F00\u8DEF\u5F84
\ No newline at end of file
diff --git a/src/main/resources/lang/I18N_zh_TW.properties b/src/main/resources/lang/I18N_zh_TW.properties
index 83951b4..ecc3109 100644
--- a/src/main/resources/lang/I18N_zh_TW.properties
+++ b/src/main/resources/lang/I18N_zh_TW.properties
@@ -37,8 +37,14 @@ window.unpin=\u672A\u91D8\u9078
mainWindow.tab.search=\u641C\u5C0B
mainWindow.tab.quickEdit=\u5FEB\u901F\u7DE8\u8F2F
mainWindow.tab.setting=\u8A2D\u5B9A
-search.text=\u641C\u5C0B\u6846
+search.promptText=\u641C\u5C0B\u6846
setting.startOnBoot.label=\u958B\u6A5F\u81EA\u555F\u52D5
alert.exit.title=\u932F\u8AA4
alert.exit.headText=\u7CFB\u7D71\u4E0D\u652F\u63F4
-alert.exit.contentText=Vortex \u50C5\u652F\u63F4\u5728 Windows \u7CFB\u7D71\u4E0A\u57F7\u884C\n\u4E0D\u652F\u63F4\u5728 Linux\u3001Mac \u6216\u5176\u4ED6\u7CFB\u7D71\u4E0A\u57F7\u884C
\ No newline at end of file
+alert.exit.contentText=Vortex \u50C5\u652F\u63F4\u5728 Windows \u7CFB\u7D71\u4E0A\u57F7\u884C\n\u4E0D\u652F\u63F4\u5728 Linux\u3001Mac \u6216\u5176\u4ED6\u7CFB\u7D71\u4E0A\u57F7\u884C
+search.pending.text=\u9375\u5165\u6587\u5B57\u4EE5\u641C\u5C0B
+search.result.notFound.text=\u6C92\u627E\u5230\u4EFB\u4F55\u7D50\u679C\uFF0C\u5617\u8A66\u63DB\u4E00\u500B\u95DC\u9375\u8A5E\u641C\u5C0B
+file.open.tip=\u958B\u555F
+file.openInFolder.tip=\u5728\u8CC7\u6599\u593E\u4E2D\u986F\u793A
+file.copyPath.tip=\u8907\u88FD\u6A94\u6848\u8DEF\u5F91
+file.openPathInTerminal.tip=\u5728\u63A7\u5236\u53F0\u4E2D\u958B\u555F\u8DEF\u5F91
\ No newline at end of file
diff --git a/src/main/resources/tech/minediamond/vortex/css/dark-theme.css b/src/main/resources/tech/minediamond/vortex/css/dark-theme.css
index 8ffc65f..2b7638a 100644
--- a/src/main/resources/tech/minediamond/vortex/css/dark-theme.css
+++ b/src/main/resources/tech/minediamond/vortex/css/dark-theme.css
@@ -67,6 +67,10 @@
-fx-setting-combo-box-popup-bg-color-pressed: #5f5f5f;/*设置条目单选按钮弹出框按下时背景颜色*/
-fx-setting-combo-box-arrow-border-color: #e0e0e0;/* 设置条目单选按钮箭头边框颜色*/
+ /*搜索面板样式*/
+ -fx-search-result-file-path-text-color: #cdcdcd;/*搜索面板文件路径文本颜色*/
+ -fx-search-result-card-bg-color-hover:#474747;/*搜索面板列表悬浮时背景颜色*/
+
/*特殊样式*/
-fx-exit-button-bg-color-hover:#b34646;/*退出按钮悬浮时背景颜色*/
-fx-exit-button-bg-color-pressed: #c64d4d;/*退出按钮悬浮时背景颜色*/
diff --git a/src/main/resources/tech/minediamond/vortex/css/fluent-style.css b/src/main/resources/tech/minediamond/vortex/css/fluent-style.css
index 2b52350..39c12c4 100644
--- a/src/main/resources/tech/minediamond/vortex/css/fluent-style.css
+++ b/src/main/resources/tech/minediamond/vortex/css/fluent-style.css
@@ -75,6 +75,10 @@
-fx-setting-combo-box-popup-bg-color-pressed: #b9b9be;/*设置条目单选按钮弹出框按下时背景颜色*/
-fx-setting-combo-box-arrow-border-color: #353333;/* 设置条目单选按钮箭头边框颜色*/
+ /*搜索面板样式*/
+ -fx-search-result-file-path-text-color: #cdcdcd;/*搜索面板文件路径文本颜色*/
+ -fx-search-result-card-bg-color-hover:#474747;/*搜索面板列表悬浮时背景颜色*/
+
/*特殊样式*/
-fx-exit-button-bg-color-hover: #f86868;/*退出按钮悬浮时背景颜色*/
-fx-exit-button-bg-color-pressed: #e86363;/*退出按钮悬浮时背景颜色*/
@@ -392,6 +396,38 @@
}
+/* ===搜索结果卡片=== */
+
+.search-result-card {
+ -fx-min-height: 50;
+ -fx-alignment: CENTER_LEFT;
+ -fx-background-radius: 4px; /* 圆角 */
+ -fx-border-radius: 4px; /* 边框也需要圆角 */
+ -fx-spacing: 2;
+ -fx-padding: 5 5 5 5;
+}
+
+.search-result-card:hover {
+ -fx-background-color: -fx-search-result-card-bg-color-hover;
+}
+
+.search-result-card .search-result-file-path {
+ -fx-text-fill: -fx-search-result-file-path-text-color;
+ -fx-font-size: 11px;
+}
+
+.search-result-card .button{
+ -fx-min-width: 35;
+ -fx-pref-height: 30;
+}
+
+.search-result-card .button:hover{
+ -fx-background-color: -fx-setting-list-button-bg-color-hover;
+}
+
+.search-result-card .button:pressed{
+ -fx-background-color: -fx-setting-list-button-bg-color-pressed;
+}
/* ===特殊按钮=== */
#pinBtn:selected .ikonli-font-icon{
diff --git a/src/main/resources/tech/minediamond/vortex/css/light-theme.css b/src/main/resources/tech/minediamond/vortex/css/light-theme.css
index a8cc6fc..b224c1e 100644
--- a/src/main/resources/tech/minediamond/vortex/css/light-theme.css
+++ b/src/main/resources/tech/minediamond/vortex/css/light-theme.css
@@ -67,6 +67,10 @@
-fx-setting-combo-box-popup-bg-color-pressed: #b9b9be;/*设置条目单选按钮弹出框按下时背景颜色*/
-fx-setting-combo-box-arrow-border-color: #353333;/* 设置条目单选按钮箭头边框颜色*/
+ /*搜索面板样式*/
+ -fx-search-result-file-path-text-color: #636363;/*搜索面板文件路径文本颜色*/
+ -fx-search-result-card-bg-color-hover:#d3d3d3;/*搜索面板列表悬浮时背景颜色*/
+
/*特殊样式*/
-fx-exit-button-bg-color-hover: #f86868;/*退出按钮悬浮时背景颜色*/
-fx-exit-button-bg-color-pressed: #e86363;/*退出按钮悬浮时背景颜色*/
diff --git a/src/main/resources/tech/minediamond/vortex/ui/main-window.fxml b/src/main/resources/tech/minediamond/vortex/ui/main-window.fxml
index e9ea5ce..a95e07c 100644
--- a/src/main/resources/tech/minediamond/vortex/ui/main-window.fxml
+++ b/src/main/resources/tech/minediamond/vortex/ui/main-window.fxml
@@ -34,7 +34,7 @@
-
+
@@ -42,7 +42,7 @@
-
+
diff --git a/src/main/resources/tech/minediamond/vortex/ui/searchPanel.fxml b/src/main/resources/tech/minediamond/vortex/ui/searchPanel.fxml
new file mode 100644
index 0000000..b01525b
--- /dev/null
+++ b/src/main/resources/tech/minediamond/vortex/ui/searchPanel.fxml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/tech/minediamond/vortex/service/EverythingServiceTest.java b/src/test/java/tech/minediamond/vortex/service/EverythingServiceTest.java
index 1fa653b..da8eae1 100644
--- a/src/test/java/tech/minediamond/vortex/service/EverythingServiceTest.java
+++ b/src/test/java/tech/minediamond/vortex/service/EverythingServiceTest.java
@@ -23,10 +23,9 @@
import com.google.inject.Inject;
import com.google.inject.Injector;
import tech.minediamond.vortex.config.AppModule;
-import tech.minediamond.vortex.model.search.EverythingResult;
+import tech.minediamond.vortex.model.fileData.FileData;
import tech.minediamond.vortex.model.search.SearchMode;
import tech.minediamond.vortex.service.search.EverythingService;
-import tech.minediamond.vortex.util.OpenResourceUtil;
import java.io.IOException;
import java.nio.file.Path;
@@ -51,7 +50,7 @@ public static void main(String[] args) throws IOException, InterruptedException
ArrayList folders = new ArrayList<>();
folders.add(Paths.get("D:\\myDounment"));
folders.add(Paths.get("F:\\software_play_in_F"));
- List results = everythingServiceTest.service.QueryBuilder()
+ List results = everythingServiceTest.service.QueryBuilder()
.searchFor("askding")
.inFolders(folders)
.mode(SearchMode.ALL)