mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-20 10:37:27 +08:00
GP-5333 Added repo connection status/action to root project data tree node
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 20 KiB |
+28
-17
@@ -40,27 +40,38 @@
|
||||
<H2><A name="ConnectToServer"></A>Connect to the Server</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>When you open a shared project, Ghidra attempts to connect to the server that is
|
||||
associated with the shared project. Depending on what user authentication mode the server is
|
||||
using, you may have to enter a password. If the server is not running, you are still able to
|
||||
work with your checked out files while you are offline. Other versioned files not checked out
|
||||
are not accessible. When the server comes up, Ghidra will reconnect as necessary. You can
|
||||
also attempt to connect "manually" by selecting the connection status button <IMG alt="" src=
|
||||
"images/disconnected.gif" border="0"> on the Ghidra Project Window or on the <I><A href=
|
||||
"help/topics/FrontEndPlugin/Project_Info.htm">Project Info</A></I> dialog. When the
|
||||
connection is successful, the connection status button changes to <IMG alt="" src=
|
||||
"images/connected.gif" border="0">. </P>
|
||||
|
||||
<P>If you lose the connection to the server after having started Ghidra, shared files not
|
||||
checked out "disappear" from the Ghidra Project Window, as they are unavailable. Private
|
||||
files remain intact and are not affected by the server connection.</P>
|
||||
<P>When you open or view a shared project, Ghidra attempts to connect to the corresponding server.
|
||||
Depending on which user authentication mode the server is using, you may have to enter a password.
|
||||
If you choose not to connect or lose the connection to the repository server after opening
|
||||
or viewing a project, shared files not
|
||||
checked out will not be shown within the Ghidra Project Window, as they are unavailable for use.
|
||||
Local project private files are not affected by the repository server connection and will always
|
||||
be shown. If you subsequently connect to the repository server, Ghidra will refresh
|
||||
the project views to reflect the current state. </P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
<IMG SRC="help/shared/tip.png" />
|
||||
The root folder node of the Project Data Tree view of a shared project will convey the
|
||||
current connection status with green (connected) or red (disconnected) indicator. </P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P>If applicable, and
|
||||
not currently connected to the shared repository server, a manual connection may be re-attempted by
|
||||
clicking the <B>Connect Shared Repository</B> popup action on the root node of a shared project.
|
||||
For the active project there is also a Connect status button in the lower-right corner of the
|
||||
project window. When this button shows the disconnected state
|
||||
<IMG alt="" src="images/disconnected.gif" border="0"> it may be clicked to attempt a connection.
|
||||
This may also be done from the <I><A href="help/topics/FrontEndPlugin/Project_Info.htm">Project
|
||||
Info</A></I> dialog. When the active project repository connection is successful, the connection
|
||||
status button changes to <IMG alt="" src="images/connected.gif" border="0">. </P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
<IMG SRC="help/shared/tip.png" />
|
||||
You are authenticated only once per
|
||||
Ghidra session; so if you open other project repositories managed by the same Ghidra Server,
|
||||
you will be prompted only once for a password, as required. </P>
|
||||
Successfully connecting to a Ghidra Server which corresponds to multiple named repositories will cause
|
||||
all associated viewed projects within Ghidra to become connected or automatically connect
|
||||
when subsequently opened. </P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Troubleshooting"></A>Troubleshooting a Failed Connection</H3>
|
||||
|
||||
@@ -26,6 +26,7 @@ src/main/resources/images/checkNotLatest.gif||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/checkex.png||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/connected.gif||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/disconnected.gif||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/green_can.png||GHIDRA||||END|
|
||||
src/main/resources/images/link.png||Crystal Clear Icons - LGPL 2.1||||END|
|
||||
src/main/resources/images/lock.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/resources/images/monitor.png||FAMFAMFAM Icons - CC 2.5|||silk|END|
|
||||
@@ -34,6 +35,7 @@ src/main/resources/images/page_delete.png||FAMFAMFAM Icons - CC 2.5||||END|
|
||||
src/main/resources/images/page_edit.png||FAMFAMFAM Icons - CC 2.5||||END|
|
||||
src/main/resources/images/plasma.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
||||
src/main/resources/images/plugin.png||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/red_can.png||GHIDRA||||END|
|
||||
src/main/resources/images/small_hijack.gif||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/undo_hijack.png||GHIDRA||reviewed||END|
|
||||
src/main/resources/images/unknownFile.gif||GHIDRA||reviewed||END|
|
||||
|
||||
@@ -9,6 +9,12 @@ icon.project.data.file.ghidra.hijacked = small_hijack.gif
|
||||
icon.project.data.file.ghidra.read.only = user-busy.png [size(8,8)]
|
||||
icon.project.data.file.ghidra.not.latest = checkNotLatest.gif
|
||||
|
||||
icon.project.root.repo.connected = green_can.png
|
||||
icon.project.root.repo.connected.overlay = EMPTY_ICON[size(18,16)]{icon.project.root.repo.connected[move(12,8)]} // lower-left of 16x16 icon
|
||||
|
||||
icon.project.root.repo.disconnected = red_can.png
|
||||
icon.project.root.repo.disconnected.overlay = EMPTY_ICON[size(18,16)]{icon.project.root.repo.disconnected[move(12,8)]} // lower-left of 16x16 icon
|
||||
|
||||
icon.content.handler.link = link.png
|
||||
icon.content.handler.link.overlay = EMPTY_ICON[size(16,16)]{icon.content.handler.link[move(0,8)]} // lower-left of 16x16 icon
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@ public class FrontEndPlugin extends Plugin
|
||||
|
||||
private FrontEndProvider frontEndProvider;
|
||||
|
||||
private ProjectRepoConnectAction repoConnectAction;
|
||||
private ProjectDataCutAction cutAction;
|
||||
private ClearCutAction clearCutAction;
|
||||
private ProjectDataCopyAction copyAction;
|
||||
@@ -221,6 +222,7 @@ public class FrontEndPlugin extends Plugin
|
||||
String owner = getName();
|
||||
|
||||
// Top of popup menu actions - no group
|
||||
repoConnectAction = new ProjectRepoConnectAction(this, null);
|
||||
openAction = new ProjectDataOpenDefaultToolAction(owner, null);
|
||||
followLinkAction = new ProjectDataFollowLinkAction(this, null);
|
||||
selectRealFileOrFolderAction = new ProjectDataSelectRealFileOrFolderAction(this, null);
|
||||
@@ -251,6 +253,7 @@ public class FrontEndPlugin extends Plugin
|
||||
groupName = "XRefresh";
|
||||
refreshAction = new ProjectDataRefreshAction(owner, groupName);
|
||||
|
||||
tool.addAction(repoConnectAction);
|
||||
tool.addAction(newFolderAction);
|
||||
tool.addAction(cutAction);
|
||||
tool.addAction(clearCutAction);
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.framework.main;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import docking.action.MenuData;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.framework.client.*;
|
||||
import ghidra.framework.main.datatable.FrontendProjectTreeAction;
|
||||
import ghidra.framework.main.datatable.ProjectDataContext;
|
||||
import ghidra.framework.main.datatree.DataTree;
|
||||
import ghidra.framework.model.DomainFolder;
|
||||
import ghidra.framework.model.ProjectData;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
/**
|
||||
* {@link ProjectRepoConnectAction} action allows the user to initiate a shared repository
|
||||
* connection for a root shared project data tree node that is not currently connected.
|
||||
*/
|
||||
public class ProjectRepoConnectAction extends FrontendProjectTreeAction {
|
||||
|
||||
private static final Icon CONNECT_ICON = new GIcon("icon.frontend.project.connected");
|
||||
|
||||
private FrontEndPlugin plugin;
|
||||
|
||||
public ProjectRepoConnectAction(FrontEndPlugin plugin, String group) {
|
||||
super("Connect Shared Repository", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
setPopupMenuData(
|
||||
new MenuData(new String[] { "Connect Shared Repository" }, CONNECT_ICON, group));
|
||||
setHelpLocation(new HelpLocation("VersionControl", "Connect_Shared_Repository"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(ProjectDataContext context) {
|
||||
RepositoryAdapter repository = getDisconnectedRepository(context);
|
||||
if (repository != null) {
|
||||
try {
|
||||
repository.connect();
|
||||
}
|
||||
catch (NotConnectedException e) {
|
||||
// don't think this can happen
|
||||
}
|
||||
catch (IOException e) {
|
||||
ClientUtil.handleException(repository, e, "Repository Connection",
|
||||
plugin.getTool().getToolFrame());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabledForContext(ProjectDataContext context) {
|
||||
return getDisconnectedRepository(context) != null;
|
||||
}
|
||||
|
||||
private RepositoryAdapter getDisconnectedRepository(ProjectDataContext context) {
|
||||
if (!(context.getComponent() instanceof DataTree)) {
|
||||
return null;
|
||||
}
|
||||
if (context.getFolderCount() != 1 || context.getFileCount() != 0) {
|
||||
return null;
|
||||
}
|
||||
DomainFolder domainFolder = context.getSelectedFolders().get(0);
|
||||
if (domainFolder.getParent() != null) {
|
||||
return null;
|
||||
}
|
||||
ProjectData projectData = domainFolder.getProjectData();
|
||||
if (projectData.getProjectLocator().isTransient()) {
|
||||
return null; // Transient projects are always connected
|
||||
}
|
||||
RepositoryAdapter repository = projectData.getRepository();
|
||||
if (repository != null && !repository.isConnected()) {
|
||||
return repository;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+74
-12
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -21,23 +21,81 @@ import javax.swing.Icon;
|
||||
|
||||
import docking.tool.ToolConstants;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.framework.client.RemoteAdapterListener;
|
||||
import ghidra.framework.client.RepositoryAdapter;
|
||||
import ghidra.framework.model.*;
|
||||
import resources.MultiIcon;
|
||||
|
||||
public class DomainFolderRootNode extends DomainFolderNode implements RemoteAdapterListener {
|
||||
|
||||
public class DomainFolderRootNode extends DomainFolderNode {
|
||||
private static final Icon CLOSED_PROJECT = new GIcon("icon.datatree.node.domain.folder.closed");
|
||||
private static final Icon OPEN_PROJECT = new GIcon("icon.datatree.node.domain.folder.open");
|
||||
|
||||
private static final Icon CONNECTED_OVERLAY =
|
||||
new GIcon("icon.project.root.repo.connected.overlay");
|
||||
private static final Icon DISCONNECTED_OVERLAY =
|
||||
new GIcon("icon.project.root.repo.disconnected.overlay");
|
||||
|
||||
private static enum Status {
|
||||
OPEN(true),
|
||||
CLOSED(false),
|
||||
OPEN_CONNECTED(true, true),
|
||||
CLOSED_CONNECTED(false, true),
|
||||
OPEN_DISCONNECTED(true, false),
|
||||
CLOSED_DISCONNECTED(false, false);
|
||||
|
||||
final Icon icon;
|
||||
|
||||
private Status(boolean isOpen) {
|
||||
icon = isOpen ? OPEN_PROJECT : CLOSED_PROJECT;
|
||||
}
|
||||
|
||||
private Status(boolean isOpen, boolean isConnected) {
|
||||
MultiIcon multiIcon = new MultiIcon(isOpen ? OPEN_PROJECT : CLOSED_PROJECT);
|
||||
multiIcon.addIcon(isConnected ? CONNECTED_OVERLAY : DISCONNECTED_OVERLAY);
|
||||
icon = multiIcon;
|
||||
}
|
||||
|
||||
static Status getStatus(boolean isOpen, RepositoryAdapter repository) {
|
||||
if (isOpen) {
|
||||
if (repository == null) {
|
||||
return OPEN;
|
||||
}
|
||||
return repository.isConnected() ? OPEN_CONNECTED : OPEN_DISCONNECTED;
|
||||
}
|
||||
if (repository == null) {
|
||||
return CLOSED;
|
||||
}
|
||||
return repository.isConnected() ? CLOSED_CONNECTED : CLOSED_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
private String projectName;
|
||||
private RepositoryAdapter repository;
|
||||
|
||||
private Status status;
|
||||
private String toolTipText;
|
||||
|
||||
DomainFolderRootNode(String projectName, DomainFolder rootFolder, ProjectData projectData,
|
||||
DomainFileFilter filter) {
|
||||
super(rootFolder, filter);
|
||||
this.projectName = projectName;
|
||||
this.repository = getProjectData().getRepository();
|
||||
if (repository != null) {
|
||||
repository.addListener(this);
|
||||
}
|
||||
|
||||
toolTipText = getToolTip(projectData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (repository != null) {
|
||||
repository.removeListener(this);
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (projectName == null) {
|
||||
@@ -58,21 +116,25 @@ public class DomainFolderRootNode extends DomainFolderNode {
|
||||
|
||||
@Override
|
||||
public Icon getIcon(boolean expanded) {
|
||||
return expanded ? OPEN_PROJECT : CLOSED_PROJECT;
|
||||
status = Status.getStatus(expanded, repository);
|
||||
return status.icon;
|
||||
}
|
||||
|
||||
private String getToolTip(ProjectData projectData) {
|
||||
RepositoryAdapter repository = projectData.getRepository();
|
||||
File dir = projectData.getProjectLocator().getProjectDir();
|
||||
ProjectLocator projectLocator = projectData.getProjectLocator();
|
||||
File dir = projectLocator.getProjectDir();
|
||||
String toolTip = dir.getAbsolutePath();
|
||||
if (!getDomainFolder().isInWritableProject() && repository != null) {
|
||||
if (!projectLocator.isTransient() && repository != null) {
|
||||
ServerInfo info = repository.getServerInfo();
|
||||
String serverName = "";
|
||||
if (info != null) {
|
||||
serverName = info.getServerName() + ", ";
|
||||
}
|
||||
toolTip += " [" + serverName + repository.getName() + "]";
|
||||
String serverName = info.getServerName() + ":";
|
||||
String statusText = repository.isConnected() ? "connected" : "disconnected";
|
||||
toolTip += " [" + serverName + repository.getName() + ", " + statusText + "]";
|
||||
}
|
||||
return toolTip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionStateChanged(Object adapter) {
|
||||
toolTipText = getToolTip(getProjectData());
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 249 B |
Binary file not shown.
|
After Width: | Height: | Size: 262 B |
+4
-2
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -76,6 +76,7 @@ public class VersionControlScreenShots extends GhidraScreenShotGenerator {
|
||||
|
||||
UndoActionDialog d = waitForDialogComponent(UndoActionDialog.class);
|
||||
captureDialog(d);
|
||||
close(d);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -95,6 +96,7 @@ public class VersionControlScreenShots extends GhidraScreenShotGenerator {
|
||||
|
||||
UndoActionDialog d = waitForDialogComponent(UndoActionDialog.class);
|
||||
captureDialog(d);
|
||||
close(d);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user