/[svn]/jsampler/trunk/src/org/jsampler/view/classic/ClassicPrefs.java
ViewVC logotype

Contents of /jsampler/trunk/src/org/jsampler/view/classic/ClassicPrefs.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2288 - (show annotations) (download)
Wed Nov 23 21:19:44 2011 UTC (12 years, 5 months ago) by iliev
File size: 20807 byte(s)
* Added option to select a sampler engine in Add/Edit Instrument dialog
* Moved all Swing dependent code outside the JSampler core

1 /*
2 * JSampler - a java front-end for LinuxSampler
3 *
4 * Copyright (C) 2005-2011 Grigor Iliev <grigor@grigoriliev.com>
5 *
6 * This file is part of JSampler.
7 *
8 * JSampler is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * JSampler is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with JSampler; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 */
22
23 package org.jsampler.view.classic;
24
25 import java.awt.Color;
26
27 import java.util.prefs.Preferences;
28
29 import org.jsampler.JSPrefs;
30
31
32 /**
33 * This class represents the preferences of the JS Classic package.
34 * @author Grigor Iliev
35 */
36 public class ClassicPrefs extends JSPrefs {
37 private final static String prefNode = "org.jsampler.view.classic";
38
39 private final static String WINDOW_SIZE_AND_LOCATION = ".sizeAndLocation";
40 private final static String DEF_WINDOW_SIZE_AND_LOCATION = null;
41
42 private final static String WINDOW_MAXIMIZED = ".maximized";
43 private final static boolean DEF_WINDOW_MAXIMIZED = false;
44
45 private final static String SAVE_WINDOW_PROPERTIES = "Mainframe.saveProperties";
46 private final static boolean DEF_SAVE_WINDOW_PROPERTIES = true;
47
48 private final static String HSPLIT_DIVIDER_LOCATION = "HSplit.dividerLocation";
49 private final static int DEF_HSPLIT_DIVIDER_LOCATION = 180;
50
51 private final static String SAVE_LEFT_PANE_STATE = "LeftPane.saveState";
52 private final static boolean DEF_SAVE_LEFT_PANE_STATE = true;
53
54 private final static String LEFT_PANE_PAGE_IDX = "LeftPane.pageIndex";
55 private final static int DEF_LEFT_PANE_PAGE_IDX = 0;
56
57 private final static String SHOW_CHANNELS_BAR = "ChannelsBar.visible";
58 private final static boolean DEF_SHOW_CHANNELS_BAR = true;
59
60 private final static String SHOW_STATUSBAR = "Statusbar.visible";
61 private final static boolean DEF_SHOW_STATUSBAR = true;
62
63 private final static String SHOW_LEFT_PANE = "LeftPane.visible";
64 private final static boolean DEF_SHOW_LEFT_PANE = true;
65
66 private final static String SHOW_STANDARD_BAR = "StandardBar.visible";
67 private final static boolean DEF_SHOW_STANDARD_BAR = true;
68
69 private final static String SHOW_LS_CONSOLE = "LSConsole.visible";
70 private final static boolean DEF_SHOW_LS_CONSOLE = false;
71
72 private final static String LS_CONSOLE_POPOUT = "LSConsole.popout";
73 private final static boolean DEF_LS_CONSOLE_POPOUT = false;
74
75 private final static String CHANNEL_BORDER_COLOR = "Channel.borderColor";
76 private final static int DEF_CHANNEL_BORDER_COLOR = 0xb8cfe5;
77
78 private final static String CUSTOM_CHANNEL_BORDER_COLOR = "Channel.customBorderColor";
79 private final static boolean DEF_CUSTOM_CHANNEL_BORDER_COLOR = false;
80
81 private final static String CHANNEL_BORDER_HL_COLOR = "Channel.borderMouseOverColor";
82 private final static int DEF_CHANNEL_BORDER_HL_COLOR = 0xb8cfe5;
83
84 private final static String CUSTOM_CHANNEL_BORDER_HL_COLOR = "Channel.customHlColor";
85 private final static boolean DEF_CUSTOM_CHANNEL_BORDER_HL_COLOR = false;
86
87 private final static String SEL_CHANNEL_BG_COLOR = "Channel.sel.BgColor";
88 private final static int DEF_SEL_CHANNEL_BG_COLOR = 0xe0e6eb;
89
90 private final static String CUSTOM_SEL_CHANNEL_BG_COLOR = "Channel.sel.customBgColor";
91 private final static boolean DEF_CUSTOM_SEL_CHANNEL_BG_COLOR = false;
92
93 private final static String HL_CHANNEL_BG_COLOR = "Channel.hl.BgColor";
94 private final static int DEF_HL_CHANNEL_BG_COLOR = -1;
95
96 private final static String CUSTOM_HL_CHANNEL_BG_COLOR = "Channel.hl.customBgColor";
97 private final static boolean DEF_CUSTOM_HL_CHANNEL_BG_COLOR = false;
98
99 private final static String VSPLIT_DIVIDER_LOCATION = "VSplit.dividerLocation";
100 private final static int DEF_VSPLIT_DIVIDER_LOCATION = 200;
101
102 private final static String CURRENT_ORCHESTRA_IDX = "OrchestrasPage.currentOrchestraIndex";
103 private final static int DEF_CURRENT_ORCHESTRA_IDX = 0;
104
105 private static Preferences userPrefs = Preferences.userRoot().node(prefNode);
106
107 private final static ClassicPrefs prefs = new ClassicPrefs();
108
109 private
110 ClassicPrefs() { super(prefNode); }
111
112 public static ClassicPrefs
113 preferences() { return prefs; }
114
115 public static Preferences
116 user() { return userPrefs; }
117
118 /**
119 * Gets a string representation of a window's size and location.
120 * The string representation is a comma-separated list
121 * of x and y coordinates, and width and height of the window.
122 * @param window The name of the window whose size and location should be obtained.
123 * @return A string representation of the window's size and location,
124 * or <code>null</code> if the value is not set.
125 */
126 public static String
127 getWindowSizeAndLocation(String window) {
128 return user().get(window + WINDOW_SIZE_AND_LOCATION, DEF_WINDOW_SIZE_AND_LOCATION);
129 }
130
131 /**
132 * Sets the window's size and location.
133 * Use <code>null</code> to remove the current value.
134 * @param window The name of the window whose size and location should be set.
135 * @param s A string representation of the window's size and location.
136 */
137 public static void
138 setWindowSizeAndLocation(String window, String s) {
139 if(s == null) {
140 user().remove(window + WINDOW_SIZE_AND_LOCATION);
141 return;
142 }
143
144 user().put(window + WINDOW_SIZE_AND_LOCATION, s);
145 }
146
147 /**
148 * Determines whether the specified window should be maximized.
149 * @param window The name of the window.
150 * @return <code>true</code> if the specified window should be maximized,
151 * <code>false</code> otherwise.
152 */
153 public static boolean
154 getWindowMaximized(String window) {
155 return user().getBoolean(window + WINDOW_MAXIMIZED, DEF_WINDOW_MAXIMIZED);
156 }
157
158 /**
159 * Sets whether the specified window should be maximized.
160 * @param window The name of the window.
161 * @param b If <code>true</code> the specified window should be maximized.
162 */
163 public static void
164 setWindowMaximized(String window, boolean b) {
165 if(b == getWindowMaximized(window)) return;
166 user().putBoolean(window + WINDOW_MAXIMIZED, b);
167 }
168
169 /**
170 * Gets the divider location of the horizontal split pane.
171 * @return The divider location of the horizontal split pane.
172 */
173 public static int
174 getHSplitDividerLocation() {
175 return user().getInt(HSPLIT_DIVIDER_LOCATION, DEF_HSPLIT_DIVIDER_LOCATION);
176 }
177
178 /**
179 * Sets the divider location of the horizontal split pane.
180 * @param i The new divider location of the horizontal split pane.
181 */
182 public static void
183 setHSplitDividerLocation(int i) {
184 if(i == getHSplitDividerLocation()) return;
185 user().putInt(HSPLIT_DIVIDER_LOCATION, i);
186 }
187
188 /**
189 * Determines whether the window properties (like size and location) should be saved.
190 * @return <code>true</code> if the window properties should be saved,
191 * <code>false</code> otherwise.
192 */
193 public static boolean
194 getSaveWindowProperties() {
195 return user().getBoolean(SAVE_WINDOW_PROPERTIES, DEF_SAVE_WINDOW_PROPERTIES);
196 }
197
198 /**
199 * Sets whether the window properties (like size and location) should be saved.
200 * @param b If <code>true</code> the window properties will be saved.
201 */
202 public static void
203 setSaveWindowProperties(boolean b) {
204 if(b == getSaveWindowProperties()) return;
205 user().putBoolean(SAVE_WINDOW_PROPERTIES, b);
206 }
207
208 /**
209 * Determines whether the Left Pane state should be saved.
210 * @return <code>true</code> if the Left Pane state should be saved,
211 * <code>false</code> otherwise.
212 */
213 public static boolean
214 getSaveLeftPaneState() {
215 return user().getBoolean(SAVE_LEFT_PANE_STATE, DEF_SAVE_LEFT_PANE_STATE);
216 }
217
218 /**
219 * Sets whether the Left Pane state should be saved.
220 * @param b If <code>true</code> the Left Pane state will be saved.
221 */
222 public static void
223 setSaveLeftPaneState(boolean b) {
224 if(b == getSaveLeftPaneState()) return;
225 user().putBoolean(SAVE_LEFT_PANE_STATE, b);
226 }
227
228 /**
229 * Gets the index of the page to be shown in the Left Pane.
230 * @return The index of the page to be shown in the Left Pane.
231 */
232 public static int
233 getLeftPanePageIndex() {
234 return user().getInt(LEFT_PANE_PAGE_IDX, DEF_LEFT_PANE_PAGE_IDX);
235 }
236
237 /**
238 * Sets the maximum number of recent scripts to be kept.
239 * @param i Determines the maximum number of recent scripts to be kept.
240 */
241 public static void
242 setLeftPanePageIndex(int i) {
243 if(i == getLeftPanePageIndex()) return;
244 user().putInt(LEFT_PANE_PAGE_IDX, i);
245 }
246
247 /**
248 * Determines whether the <b>Channels</b> toolbar should be visible.
249 * @return <code>true</code> if the <b>Channels</b> toolbar should be visible,
250 * <code>false</code> otherwise.
251 */
252 public static boolean
253 shouldShowChannelsBar() {
254 return user().getBoolean(SHOW_CHANNELS_BAR, DEF_SHOW_CHANNELS_BAR);
255 }
256
257 /**
258 * Sets whether the <b>Channels</b> toolbar should be visible.
259 * @param b If <code>true</code> the <b>Channels</b> toolbar will be visible at startup.
260 */
261 public static void
262 setShowChannelsBar(boolean b) {
263 if(b == shouldShowChannelsBar()) return;
264 user().putBoolean(SHOW_CHANNELS_BAR, b);
265 }
266
267 /**
268 * Determines whether the statusbar should be visible.
269 * @return <code>true</code> if the statusbar should be visible,
270 * <code>false</code> otherwise.
271 */
272 public static boolean
273 shouldShowStatusbar() { return user().getBoolean(SHOW_STATUSBAR, DEF_SHOW_STATUSBAR); }
274
275 /**
276 * Sets whether the statusbar should be visible.
277 * @param b If <code>true</code> the statusbar will be visible at startup.
278 */
279 public static void
280 setShowStatusbar(boolean b) {
281 if(b == shouldShowStatusbar()) return;
282 user().putBoolean(SHOW_STATUSBAR, b);
283 }
284
285 /**
286 * Determines whether the LS Console should be visible.
287 * @return <code>true</code> if the LS Console should be visible,
288 * <code>false</code> otherwise.
289 */
290 public static boolean
291 shouldShowLSConsole() { return user().getBoolean(SHOW_LS_CONSOLE, DEF_SHOW_LS_CONSOLE); }
292
293 /**
294 * Sets whether the LS Console should be visible.
295 * @param b If <code>true</code> the LS Console will be visible at startup.
296 */
297 public static void
298 setShowLSConsole(boolean b) {
299 if(b == shouldShowLSConsole()) return;
300 user().putBoolean(SHOW_LS_CONSOLE, b);
301 }
302
303 /**
304 * Determines whether the LS Console should be shown in a new window or
305 * docked in the main frame.
306 * @return <code>true</code> if the LS Console should be shown in a new window,
307 * <code>false</code> if the LS Console should be docked in the main frame.
308 */
309 public static boolean
310 isLSConsolePopOut() { return user().getBoolean(LS_CONSOLE_POPOUT, DEF_LS_CONSOLE_POPOUT); }
311
312 /**
313 * Sets whether the LS Console should be shown in a new window or
314 * docked in the main frame.
315 * @param b code>true</code> means that the LS Console will be shown in a new window;
316 * <code>false</code> means that the LS Console will be docked in the main frame.
317 */
318 public static void
319 setLSConsolePopOut(boolean b) {
320 if(b == isLSConsolePopOut()) return;
321 user().putBoolean(LS_CONSOLE_POPOUT, b);
322 }
323
324 /**
325 * Determines whether the left pane should be visible.
326 * @return <code>true</code> if the left pane should be visible,
327 * <code>false</code> otherwise.
328 */
329 public static boolean
330 shouldShowLeftPane() { return user().getBoolean(SHOW_LEFT_PANE, DEF_SHOW_LEFT_PANE); }
331
332 /**
333 * Sets whether the left pane should be visible.
334 * @param b If <code>true</code> the left pane will be visible at startup.
335 */
336 public static void
337 setShowLeftPane(boolean b) {
338 if(b == shouldShowLeftPane()) return;
339 user().putBoolean(SHOW_LEFT_PANE, b);
340 }
341
342 /**
343 * Determines whether the <b>Standard</b> toolbar should be visible.
344 * @return <code>true</code> if the <b>Standard</b> toolbar should be visible,
345 * <code>false</code> otherwise.
346 */
347 public static boolean
348 shouldShowStandardBar() {
349 return user().getBoolean(SHOW_STANDARD_BAR, DEF_SHOW_STANDARD_BAR);
350 }
351
352 /**
353 * Sets whether the <b>Standard</b> toolbar should be visible.
354 * @param b If <code>true</code> the <b>Standard</b> toolbar will be visible at startup.
355 */
356 public static void
357 setShowStandardBar(boolean b) {
358 if(b == shouldShowStandardBar()) return;
359 user().putBoolean(SHOW_STANDARD_BAR, b);
360 }
361
362 /**
363 * Gets the default border color that is used for the selected channels.
364 * @return The default border color that is used for the selected channels.
365 */
366 public static Color
367 getDefaultChannelBorderColor() { return new Color(DEF_CHANNEL_BORDER_COLOR); }
368
369 /**
370 * Gets the custom border color to be used for the selected channels.
371 * @return The custom border color to be used for the selected
372 * channels or <code>null</code> if the color is not specified.
373 */
374 public static Color
375 getChannelBorderColor() {
376 int c = user().getInt(CHANNEL_BORDER_COLOR, DEF_CHANNEL_BORDER_COLOR);
377 return new Color(c);
378 }
379
380 /**
381 * Sets the border color to be used for the selected channels.
382 * Use <code>null</code> to remove the current value.
383 * @param color The border color to be used for the selected channels.
384 */
385 public static void
386 setChannelBorderColor(Color c) {
387 if(c == null) {
388 user().remove(CHANNEL_BORDER_COLOR);
389 return;
390 }
391
392 if(c.getRGB() == getChannelBorderColor().getRGB()) return;
393
394 user().putInt(CHANNEL_BORDER_COLOR, c.getRGB());
395 }
396
397 /**
398 * Determines whether to use a custom border color for the selected channels.
399 * @return <code>true</code> if custom border color must be used
400 * for the selected channels, <code>false</code> otherwise.
401 */
402 public static boolean
403 getCustomChannelBorderColor() {
404 return user().getBoolean (
405 CUSTOM_CHANNEL_BORDER_COLOR, DEF_CUSTOM_CHANNEL_BORDER_COLOR
406 );
407 }
408
409 /**
410 * Sets whether to use a custom border color for the selected channels.
411 * @param b specify <code>true</code> to use a custom border color
412 * for the selected channels, <code>false</code> otherwise.
413 */
414 public static void
415 setCustomChannelBorderColor(boolean b) {
416 if(b == getCustomChannelBorderColor()) return;
417 user().putBoolean(CUSTOM_CHANNEL_BORDER_COLOR, b);
418 }
419
420 /**
421 * Gets the default highlighted border color that
422 * is used when the mouse pointer is over a channel.
423 * @return The default highlighted border color.
424 */
425 public static Color
426 getDefaultChannelBorderHlColor() { return new Color(DEF_CHANNEL_BORDER_HL_COLOR); }
427
428 /**
429 * Gets the custom highlighted border color that
430 * is used when the mouse pointer is over a channel.
431 * @return The custom highlighted border color.
432 */
433 public static Color
434 getChannelBorderHlColor() {
435 int c = user().getInt(CHANNEL_BORDER_HL_COLOR, DEF_CHANNEL_BORDER_HL_COLOR);
436 return new Color(c);
437 }
438
439 /**
440 * Sets the highlighted border color that
441 * is used when the mouse pointer is over a channel.
442 * Use <code>null</code> to remove the current value.
443 * @param color The new highlighted border color.
444 */
445 public static void
446 setChannelBorderHlColor(Color c) {
447 if(c == null) {
448 user().remove(CHANNEL_BORDER_HL_COLOR);
449 return;
450 }
451
452 if(c.getRGB() == getChannelBorderHlColor().getRGB()) return;
453
454 user().putInt(CHANNEL_BORDER_HL_COLOR, c.getRGB());
455 }
456
457 /**
458 * Determines whether to use a custom highlighted border color.
459 * @return <code>true</code> if custom highlighted border color
460 * must be used, <code>false</code> otherwise.
461 */
462 public static boolean
463 getCustomChannelBorderHlColor() {
464 return user().getBoolean (
465 CUSTOM_CHANNEL_BORDER_HL_COLOR, DEF_CUSTOM_CHANNEL_BORDER_HL_COLOR
466 );
467 }
468
469 /**
470 * Sets whether to use a custom highlighted border color.
471 * @param b specify <code>true</code> to use a custom highlighted
472 * border color, <code>false</code> otherwise.
473 */
474 public static void
475 setCustomChannelBorderHlColor(boolean b) {
476 if(b == getCustomChannelBorderHlColor()) return;
477 user().putBoolean(CUSTOM_CHANNEL_BORDER_HL_COLOR, b);
478 }
479
480 /**
481 * Gets the custom background color that
482 * is used when the channel is selected.
483 * @return The custom background color that
484 * is used when the channel is selected.
485 */
486 public static Color
487 getSelectedChannelBgColor() {
488 int c = user().getInt(SEL_CHANNEL_BG_COLOR, DEF_SEL_CHANNEL_BG_COLOR);
489 return c == -1 ? null : new Color(c);
490 }
491
492 /**
493 * Sets the custom background color to
494 * be used when the channel is selected.
495 * Use <code>null</code> to remove the current value.
496 * @param color The new background color to
497 * be used when the channel is selected.
498 */
499 public static void
500 setSelectedChannelBgColor(Color c) {
501 if(c == null) {
502 user().remove(SEL_CHANNEL_BG_COLOR);
503 return;
504 }
505
506 if(getSelectedChannelBgColor() != null) {
507 if(c.getRGB() == getSelectedChannelBgColor().getRGB()) return;
508 }
509
510 user().putInt(SEL_CHANNEL_BG_COLOR, c.getRGB());
511 }
512
513 /**
514 * Determines whether to use a custom background color when a channel is selected.
515 * @return <code>true</code> if custom background color
516 * should be used, <code>false</code> otherwise.
517 */
518 public static boolean
519 getCustomSelectedChannelBgColor() {
520 return user().getBoolean (
521 CUSTOM_SEL_CHANNEL_BG_COLOR, DEF_CUSTOM_SEL_CHANNEL_BG_COLOR
522 );
523 }
524
525 /**
526 * Sets whether to use a custom background color when a channel is selected.
527 * @param b specify <code>true</code> to use a custom
528 * background color, <code>false</code> otherwise.
529 */
530 public static void
531 setCustomSelectedChannelBgColor(boolean b) {
532 if(b == getCustomSelectedChannelBgColor()) return;
533 user().putBoolean(CUSTOM_SEL_CHANNEL_BG_COLOR, b);
534 }
535
536 /**
537 * Gets the custom background color that
538 * is used when the mouse pointer is over a channel.
539 * @return The custom background color that
540 * is used when the mouse pointer is over a channel.
541 */
542 public static Color
543 getHighlightedChannelBgColor() {
544 int c = user().getInt(HL_CHANNEL_BG_COLOR, DEF_HL_CHANNEL_BG_COLOR);
545 return c == -1 ? null : new Color(c);
546 }
547
548 /**
549 * Sets the custom background color to
550 * be used when the mouse pointer is over a channel.
551 * Use <code>null</code> to remove the current value.
552 * @param color The new background color to
553 * be used when the mouse pointer is over a channel.
554 */
555 public static void
556 setHighlightedChannelBgColor(Color c) {
557 if(c == null) {
558 user().remove(HL_CHANNEL_BG_COLOR);
559 return;
560 }
561
562 if(getHighlightedChannelBgColor() != null) {
563 if(c.getRGB() == getHighlightedChannelBgColor().getRGB()) return;
564 }
565
566 user().putInt(HL_CHANNEL_BG_COLOR, c.getRGB());
567 }
568
569 /**
570 * Determines whether to use a custom background
571 * color when the mouse pointer is over a channel.
572 * @return <code>true</code> if custom background color
573 * should be used, <code>false</code> otherwise.
574 */
575 public static boolean
576 getCustomHighlightedChannelBgColor() {
577 return user().getBoolean (
578 CUSTOM_HL_CHANNEL_BG_COLOR, DEF_CUSTOM_HL_CHANNEL_BG_COLOR
579 );
580 }
581
582 /**
583 * Sets whether to use a custom background
584 * color when the mouse pointer is over a channel.
585 * @param b specify <code>true</code> to use a custom
586 * background color, <code>false</code> otherwise.
587 */
588 public static void
589 setCustomHighlightedChannelBgColor(boolean b) {
590 if(b == getCustomHighlightedChannelBgColor()) return;
591 user().putBoolean(CUSTOM_HL_CHANNEL_BG_COLOR, b);
592 }
593
594 /**
595 * Gets the divider location of the vertical split pane.
596 * @return The divider location of the vertical split pane.
597 */
598 public static int
599 getVSplitDividerLocation() {
600 return user().getInt(VSPLIT_DIVIDER_LOCATION, DEF_VSPLIT_DIVIDER_LOCATION);
601 }
602
603 /**
604 * Sets the divider location of the vertical split pane.
605 * @param i The new divider location of the vertical split pane.
606 */
607 public static void
608 setVSplitDividerLocation(int i) {
609 if(i == getVSplitDividerLocation()) return;
610 user().putInt(VSPLIT_DIVIDER_LOCATION, i);
611 }
612
613 /**
614 * Gets the current orchestra index of the last session.
615 * @return The current orchestra index of the last session.
616 */
617 public static int
618 getCurrentOrchestraIndex() {
619 return user().getInt(CURRENT_ORCHESTRA_IDX, DEF_CURRENT_ORCHESTRA_IDX);
620 }
621
622 /**
623 * Sets the current orchestra index.
624 * @param i The orchestra index to be set as current.
625 */
626 public static void
627 setCurrentOrchestraIndex(int i) {
628 if(i == getCurrentOrchestraIndex()) return;
629 user().putInt(CURRENT_ORCHESTRA_IDX, i);
630 }
631
632 public int
633 getDefaultIntValue(String name) {
634 if(name == LS_CONSOLE_BACKGROUND_COLOR) return 0xffffff;
635 if(name == LS_CONSOLE_TEXT_COLOR) return 0x000000;
636 if(name == LS_CONSOLE_NOTIFY_COLOR) return 0xcccccc;
637 if(name == LS_CONSOLE_WARNING_COLOR) return 0x6699ff;
638 if(name == LS_CONSOLE_ERROR_COLOR) return 0xff0000;
639
640 return super.getDefaultIntValue(name);
641 }
642 }

  ViewVC Help
Powered by ViewVC