37
37
38
38
import java .awt .*;
39
39
import java .io .File ;
40
+ import java .util .HashMap ;
41
+ import java .util .Map ;
40
42
import java .util .Objects ;
41
43
import java .util .concurrent .CompletableFuture ;
42
44
import java .util .concurrent .atomic .AtomicBoolean ;
@@ -50,7 +52,8 @@ public static EmbeddedBrowser getInstance(@NotNull Project project) {
50
52
return Objects .requireNonNull (project .getService (EmbeddedBrowser .class ));
51
53
}
52
54
53
- private Browser browser ;
55
+ private final Map <@ NotNull String , @ NotNull Browser > browsers = new HashMap <>();
56
+ private final Map <@ NotNull String , @ NotNull Content > contents = new HashMap <>();
54
57
private CompletableFuture <DevToolsUrl > devToolsUrlFuture ;
55
58
56
59
private EmbeddedBrowser (Project project ) {
@@ -61,18 +64,46 @@ private EmbeddedBrowser(Project project) {
61
64
System .setProperty ("jxbrowser.logging.level" , "ALL" );
62
65
}
63
66
67
+ ProjectManager .getInstance ().addProjectManagerListener (project , new ProjectManagerListener () {
68
+ @ Override
69
+ public void projectClosing (@ NotNull Project project ) {
70
+ for (final String key : browsers .keySet ()) {
71
+ final Browser browser = browsers .get (key );
72
+ if (browser != null ) {
73
+ try {
74
+ browser .close ();
75
+ } catch (Exception ex ) {
76
+ LOG .info (ex );
77
+ }
78
+ browsers .remove (key );
79
+ }
80
+ }
81
+ contents .clear ();
82
+ }
83
+ });
84
+ }
85
+
86
+ private void openBrowserInstanceFor (String tabName ) {
64
87
try {
65
88
final Engine engine = EmbeddedBrowserEngine .getInstance ().getEngine ();
66
89
if (engine == null ) {
67
90
return ;
68
91
}
69
-
70
- this .browser = engine .newBrowser ();
71
- browser .settings ().enableTransparentBackground ();
72
- browser .on (ConsoleMessageReceived .class , event -> {
92
+ final Browser newBrowser = engine .newBrowser ();
93
+ newBrowser .settings ().enableTransparentBackground ();
94
+ newBrowser .on (ConsoleMessageReceived .class , event -> {
73
95
final ConsoleMessage consoleMessage = event .consoleMessage ();
74
96
LOG .info ("Browser message(" + consoleMessage .level ().name () + "): " + consoleMessage .message ());
75
97
});
98
+ final Browser oldBrowser = browsers .get (tabName );
99
+ if (oldBrowser != null ) {
100
+ try {
101
+ oldBrowser .close ();
102
+ } catch (Exception ex ) {
103
+ LOG .info (ex );
104
+ }
105
+ }
106
+ browsers .put (tabName , newBrowser );
76
107
}
77
108
catch (UnsupportedRenderingModeException ex ) {
78
109
// Skip using a transparent background if an exception is thrown.
@@ -81,22 +112,7 @@ private EmbeddedBrowser(Project project) {
81
112
LOG .info (ex );
82
113
FlutterInitializer .getAnalytics ().sendExpectedException ("jxbrowser-setup" , ex );
83
114
}
84
-
85
115
resetUrl ();
86
-
87
- ProjectManager .getInstance ().addProjectManagerListener (project , new ProjectManagerListener () {
88
- @ Override
89
- public void projectClosing (@ NotNull Project project ) {
90
- if (browser != null ) {
91
- try {
92
- browser .close ();
93
- } catch (Exception ex ) {
94
- LOG .info (ex );
95
- }
96
- browser = null ;
97
- }
98
- }
99
- });
100
116
}
101
117
102
118
/**
@@ -109,8 +125,13 @@ public void resetUrl() {
109
125
this .devToolsUrlFuture = new CompletableFuture <>();
110
126
}
111
127
112
- public void openPanel (ContentManager contentManager , String tabName , DevToolsUrl devToolsUrl , Runnable onBrowserUnavailable ) {
128
+ public void openPanel (ContentManager contentManager , @ NotNull String tabName , DevToolsUrl devToolsUrl , Runnable onBrowserUnavailable ) {
129
+ final Browser firstBrowser = browsers .get (tabName );
130
+ if (browsers .get (tabName ) == null ) {
131
+ openBrowserInstanceFor (tabName );
132
+ }
113
133
// If the browser failed to start during setup, run unavailable callback.
134
+ final Browser browser = browsers .get (tabName );
114
135
if (browser == null ) {
115
136
onBrowserUnavailable .run ();
116
137
return ;
@@ -141,6 +162,17 @@ public void openPanel(ContentManager contentManager, String tabName, DevToolsUrl
141
162
}
142
163
143
164
contentManager .removeAllContents (false );
165
+ if (contents .get (tabName ) != null ) {
166
+ contents .remove (tabName );
167
+ }
168
+ for (final Content content : contents .values ()) {
169
+ contentManager .addContent (content );
170
+ }
171
+ final Content previousContent = contents .get (tabName );
172
+ if (previousContent != null ) {
173
+ contentManager .setSelectedContent (previousContent , true );
174
+ return ;
175
+ }
144
176
final Content content = contentManager .getFactory ().createContent (null , tabName , false );
145
177
146
178
// Creating Swing component for rendering web content
@@ -158,6 +190,8 @@ public void openPanel(ContentManager contentManager, String tabName, DevToolsUrl
158
190
// TODO(helin24): Use differentiated icons for each tab and copy from devtools toolbar.
159
191
content .setIcon (FlutterIcons .Phone );
160
192
contentManager .addContent (content );
193
+ contentManager .setSelectedContent (content , true );
194
+ contents .put (tabName , content );
161
195
162
196
// This is for pulling up Chrome inspector for debugging purposes.
163
197
browser .set (PressKeyCallback .class , params -> {
@@ -227,7 +261,9 @@ private void updateUrlAndReload(Function<DevToolsUrl, DevToolsUrl> newDevToolsUr
227
261
// Reload is no longer needed - either URL has been reset or there has been no change.
228
262
return ;
229
263
}
230
- browser .navigation ().loadUrl (devToolsUrl .getUrlString ());
264
+ for (final Browser browser : browsers .values ()) {
265
+ browser .navigation ().loadUrl (devToolsUrl .getUrlString ());
266
+ }
231
267
});
232
268
}
233
269
}
0 commit comments