|
50 | 50 | import java.awt.event.ActionEvent; |
51 | 51 | import java.awt.event.ActionListener; |
52 | 52 | import java.awt.event.MouseEvent; |
| 53 | +import java.io.BufferedReader; |
53 | 54 | import java.io.File; |
54 | 55 | import java.io.IOException; |
| 56 | +import java.io.InputStreamReader; |
55 | 57 | import java.net.HttpURLConnection; |
56 | 58 | import java.net.URI; |
57 | 59 | import java.net.URISyntaxException; |
@@ -1175,7 +1177,7 @@ private javax.swing.JPanel getStatusBarPane() { |
1175 | 1177 | gbc = new GridBagConstraints(); |
1176 | 1178 | gbc.gridx = gridx; |
1177 | 1179 | gbc.gridy = 0; |
1178 | | - gbc.insets = new Insets(2, 5, 2, 2); |
| 1180 | + gbc.insets = new Insets(2, 5, 2, 10); |
1179 | 1181 | this.ivjStatusBarPane.add(this.getIconBar(), gbc); |
1180 | 1182 |
|
1181 | 1183 | gridx++; |
@@ -1207,69 +1209,175 @@ public JLabel getWarningBar() { |
1207 | 1209 | if (this.warningText == null) { |
1208 | 1210 | try { |
1209 | 1211 | this.warningText = new JLabel(); |
1210 | | - this.warningText.setName(""); |
| 1212 | + this.warningText.setName("WarningBar"); |
| 1213 | + this.warningText.setText(""); |
1211 | 1214 | } catch (java.lang.Throwable ivjExc) { |
1212 | 1215 | this.handleException(ivjExc); |
1213 | 1216 | } |
1214 | 1217 | } |
1215 | 1218 | return this.warningText; |
1216 | 1219 | } |
1217 | 1220 |
|
| 1221 | + private String iconTextString = "Administrator Notification"; |
| 1222 | + private String iconToolTipString = "View VCell Administrator Notification"; |
| 1223 | + private Color darkRed = new Color(139, 0, 0); |
1218 | 1224 | public JLabel getIconBar() { |
1219 | 1225 | if (this.iconText == null) { |
1220 | 1226 | try { |
1221 | 1227 | this.iconText = new JLabel(); |
1222 | | - this.iconText.setName(""); |
| 1228 | + this.iconText.setName("IconBarLabel"); |
1223 | 1229 | this.iconText.setIcon(VCellIcons.noteRedIcon); |
1224 | | - this.iconText.setToolTipText("View VCell Administrator Notification"); |
| 1230 | + this.iconText.setText(iconTextString); |
| 1231 | + this.iconText.setForeground(darkRed); |
| 1232 | + this.iconText.setHorizontalTextPosition(SwingConstants.RIGHT); |
| 1233 | + this.iconText.setToolTipText(iconToolTipString); |
1225 | 1234 | } catch (java.lang.Throwable ivjExc) { |
1226 | 1235 | this.handleException(ivjExc); |
1227 | 1236 | } |
1228 | 1237 | } |
1229 | 1238 | return this.iconText; |
1230 | 1239 | } |
1231 | 1240 |
|
1232 | | - //private static final String notificationsUrl = "//cfs05.cam.uchc.edu/vcell/apache_webroot/htdocs/webstart/VCell_alert/VCell_Alert.html"; |
1233 | 1241 | private void checkForNotifications() { |
1234 | | - int code = HttpURLConnection.HTTP_BAD_REQUEST; |
1235 | | - try { |
1236 | | - URL u = new URL(notificationsUrl); |
1237 | | - HttpURLConnection huc = (HttpURLConnection) u.openConnection(); |
1238 | | - huc.setRequestMethod("HEAD"); // probably cheaper than huc.setRequestMethod ("GET"); |
1239 | | - huc.connect(); |
1240 | | - code = huc.getResponseCode(); |
1241 | | - } catch (IOException e) { |
1242 | | - // we just eat the exception |
1243 | | -// e.printStackTrace(); |
1244 | | - code = HttpURLConnection.HTTP_INTERNAL_ERROR; |
1245 | | - } |
1246 | | - if (code != HttpURLConnection.HTTP_OK) { |
1247 | | - this.getIconBar().setEnabled(false); |
1248 | | - this.getIconBar().setVisible(false); |
1249 | | - } else { |
1250 | | - this.getIconBar().setEnabled(true); |
1251 | | - this.getIconBar().setVisible(true); |
| 1242 | + new SwingWorker<Integer, Void>() { |
1252 | 1243 |
|
1253 | | - Timer blinkTimer = new Timer(500, new ActionListener() { |
1254 | | - private int count = 0; |
1255 | | - private final int maxCount = 110; // 55 seconds |
| 1244 | + @Override |
| 1245 | + protected Integer doInBackground() { |
| 1246 | + int code = HttpURLConnection.HTTP_BAD_REQUEST; |
| 1247 | + try { |
| 1248 | + URL u = new URL(notificationsUrl); |
| 1249 | + HttpURLConnection huc = (HttpURLConnection) u.openConnection(); |
| 1250 | + huc.setRequestMethod("HEAD"); |
| 1251 | + huc.connect(); |
| 1252 | + code = huc.getResponseCode(); |
| 1253 | + } catch (IOException e) { |
| 1254 | + code = HttpURLConnection.HTTP_INTERNAL_ERROR; |
| 1255 | + } |
| 1256 | + return code; |
| 1257 | + } |
1256 | 1258 |
|
1257 | | - public void actionPerformed(ActionEvent e) { |
1258 | | - if (this.count >= this.maxCount) { |
1259 | | - DocumentWindow.this.getIconBar().setIcon(VCellIcons.noteRedIcon); // must remain on the noteRedIcon |
1260 | | - ((Timer) e.getSource()).stop(); |
1261 | | - } else { |
1262 | | - if (this.count % 2 == 0) { |
1263 | | - DocumentWindow.this.getIconBar().setIcon(VCellIcons.noteRedIcon); |
| 1259 | + @Override |
| 1260 | + protected void done() { |
| 1261 | + int code; |
| 1262 | + try { |
| 1263 | + code = get(); |
| 1264 | + } catch (Exception e) { |
| 1265 | + code = HttpURLConnection.HTTP_INTERNAL_ERROR; |
| 1266 | + } |
| 1267 | + if (code != HttpURLConnection.HTTP_OK) { |
| 1268 | + getIconBar().setEnabled(false); |
| 1269 | + getIconBar().setVisible(false); |
| 1270 | + return; |
| 1271 | + } |
| 1272 | + |
| 1273 | + fetchNotificationTitleAsync(); |
| 1274 | + getIconBar().setEnabled(true); |
| 1275 | + getIconBar().setVisible(true); |
| 1276 | + |
| 1277 | + Timer blinkTimer = new Timer(500, new ActionListener() { |
| 1278 | + private int count = 0; |
| 1279 | + private final int maxCount = 90; // 110 (55 seconds) |
| 1280 | + |
| 1281 | + @Override |
| 1282 | + public void actionPerformed(ActionEvent e) { |
| 1283 | + getIconBar().setText(iconTextString); |
| 1284 | + if (count >= maxCount) { // end of blinking, keep the icon, remove the text |
| 1285 | +// getIconBar().setText(""); |
| 1286 | + getIconBar().setIcon(VCellIcons.noteRedIcon); |
| 1287 | + fadeOutIconText(getIconBar()); |
| 1288 | + ((Timer) e.getSource()).stop(); |
| 1289 | + return; |
| 1290 | + } |
| 1291 | + if (count % 2 == 0) { |
| 1292 | + getIconBar().setIcon(VCellIcons.noteRedIcon); |
1264 | 1293 | } else { |
1265 | | - DocumentWindow.this.getIconBar().setIcon(VCellIcons.noteWhiteIcon); |
| 1294 | + getIconBar().setIcon(VCellIcons.noteWhiteIcon); |
| 1295 | + } |
| 1296 | + count++; |
| 1297 | + } |
| 1298 | + }); |
| 1299 | + blinkTimer.start(); |
| 1300 | + } |
| 1301 | + }.execute(); |
| 1302 | + } |
| 1303 | + private void fetchNotificationTitleAsync() { |
| 1304 | + new SwingWorker<String, Void>() { |
| 1305 | + |
| 1306 | + @Override |
| 1307 | + protected String doInBackground() { |
| 1308 | + try { |
| 1309 | + URL url = new URL(notificationsUrl); |
| 1310 | + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); |
| 1311 | + conn.setRequestMethod("GET"); // need GET to read body |
| 1312 | + conn.setConnectTimeout(5000); |
| 1313 | + conn.setReadTimeout(5000); |
| 1314 | + |
| 1315 | + try (BufferedReader br = new BufferedReader( |
| 1316 | + new InputStreamReader(conn.getInputStream()))) { |
| 1317 | + |
| 1318 | + StringBuilder sb = new StringBuilder(); |
| 1319 | + String line; |
| 1320 | + while ((line = br.readLine()) != null) { |
| 1321 | + sb.append(line); |
1266 | 1322 | } |
1267 | | - this.count++; |
| 1323 | + String html = sb.toString(); |
| 1324 | + return extractTitle(html); // may return null |
1268 | 1325 | } |
| 1326 | + } catch (Exception ignored) { |
| 1327 | + return null; // swallow silently |
1269 | 1328 | } |
1270 | | - }); |
1271 | | - blinkTimer.start(); |
1272 | | - } |
| 1329 | + } |
| 1330 | + @Override |
| 1331 | + protected void done() { |
| 1332 | + try { |
| 1333 | + String title = get(); |
| 1334 | + if (title != null && !title.isEmpty()) { |
| 1335 | + iconTextString = title; |
| 1336 | + } |
| 1337 | + } catch (Exception ignored) { |
| 1338 | + // swallow silently |
| 1339 | + } |
| 1340 | + } |
| 1341 | + }.execute(); |
| 1342 | + } |
| 1343 | + private String extractTitle(String html) { |
| 1344 | + if (html == null) return null; |
| 1345 | + |
| 1346 | + String lower = html.toLowerCase(); // case-insensitive search for <title>...</title> |
| 1347 | + int start = lower.indexOf("<title>"); |
| 1348 | + int end = lower.indexOf("</title>"); |
| 1349 | + |
| 1350 | + if (start == -1 || end == -1 || end <= start) { |
| 1351 | + return null; |
| 1352 | + } |
| 1353 | + // extract the actual title text |
| 1354 | + return html.substring(start + "<title>".length(), end).trim(); |
| 1355 | + } |
| 1356 | + private void fadeOutIconText(JLabel label) { |
| 1357 | + final int steps = 20; // number of fade increments |
| 1358 | + final int delay = 50; // ms between steps (total ~1 second) |
| 1359 | + final int r = darkRed.getRed(); |
| 1360 | + final int g = darkRed.getGreen(); |
| 1361 | + final int b = darkRed.getBlue(); |
| 1362 | + |
| 1363 | + Timer fadeTimer = new Timer(delay, null); |
| 1364 | + fadeTimer.addActionListener(new ActionListener() { |
| 1365 | + int step = 0; |
| 1366 | + |
| 1367 | + @Override |
| 1368 | + public void actionPerformed(ActionEvent e) { |
| 1369 | + float alpha = 1.0f - (float) step / steps; |
| 1370 | + if (alpha <= 0f) { |
| 1371 | + label.setText(""); // remove text completely |
| 1372 | + fadeTimer.stop(); |
| 1373 | + return; |
| 1374 | + } |
| 1375 | + Color faded = new Color(r, g, b, (int) (alpha * 255)); // create same color with decreasing alpha |
| 1376 | + label.setForeground(faded); |
| 1377 | + step++; |
| 1378 | + } |
| 1379 | + }); |
| 1380 | + fadeTimer.start(); |
1273 | 1381 | } |
1274 | 1382 |
|
1275 | 1383 | private javax.swing.JMenuItem getTestingFrameworkMenuItem() { |
|
0 commit comments