# 3.3 - New Time Zone Dialog
In this section, we will create a dialog and add it to our clock application.
![](GSPT_files/Panel-02.jpg)
You will learn:
## Creating a Panel
A Panel is a special kind of window. Read the Cocoa document for more
details: [*Windows and
Panels*](https://web.archive.org/web/20010606130438if_/https://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/ProgrammingTopics/WinPanel/index.html).
Since I have a clock already, I want to know the time in different time
zones. My idea is that when I click the title of the `NSBox`, a panel will
show up and ask the time zone. Once the time zone is inputted, it will
display the time in that area. Since `NSPanel` is a subclass of `NSWindow`,
the usage of `NSPanel` is similar to `NSWindow`. Again, I need a
"controller" to control the "view", which is `NSPanel` in this case.
The "view" is generated by Gorm, and I need to write the "controller" by
myself. In this example, I'll show how to load the gorm file. There are
many built-in panel in GNUstep. I also use one in this example.
First, we need to build the interface for the panel. Open Gorm, and choose
the menu item "Document → New Module → New Empty". Look at the palettes.
There is one for "Panel".
**Figure 4-22. Panel in Gorm**
![](GSPT_files/Panel-01.jpg)
Drag the Panel out of Palettes. Build the interface as below.
**Figure 4-23. Interface of time zone panel**
![](GSPT_files/Panel-02.jpg)
You can change the size of panel in the inspector.
Here are the attributes of the panel.
**Figure 4-24. Panel attributes**
![](GSPT_files/Panel-03.jpg)
## Controlling the panel
Now, I have the "view". Then where is the "controller"? Generally, you can
write a new class as the controller of this view, but this is a small
program, so you don't have to write a class just for the controller.
So I decide to use the class `TimeView` as the controller
for this panel. So `TimeView` acts as the custom view for that
main window interface, and as the controller for the panel. Since
`TimeView` is the controller of this panel, I need to connect the
outlets and actions. Therefore, I need to create the class `TimeView`
again in this gorm file, even though there is already one in
TimeMachine.gorm file.
```{admonition} Editor's note
This seems like a bad idea, but changing it would require a lot of refactoring of this tutorial.
```
You already know how to create the class `TimeView`. I add two outlets,
`zonePanel` and `zoneField`, and two actions, `okAction:` and
`cancelAction:`.
**Figure 4-25. Outlets for time zone panel**
![](GSPT_files/Panel-05.jpg)
**Figure 4-26. Actions for time zone panel**
![](GSPT_files/Panel-04.jpg)
But rather than creating an instance to connect to the panel, let's set the
owner of this panel to our `TimeView`. This reduces the amount of instances in our project.
Select the NSOwner in Gorm main window, then select class `TimeView` in
the Attributes tab of the inspector.
**Figure 4-27. Set NSOwner to TimeView class**
![](GSPT_files/Panel-06.jpg)
![](GSPT_files/Panel-07.jpg)
By this way, I can connect the panel to the `NSOwner`, which is an
instance of class `TimeView`. Connect the two buttons to the actions in
NSOwner, the outlet `zoneField` to the `NSTextField` in the panel, and the
outlet `zonePanel` to the panel. Pay attention to how the `NSOwner`
connects to the panel.
**Figure 4-28. Connect outlet**
![](GSPT_files/Panel-08.jpg)
![](GSPT_files/Panel-09.jpg)
Save this interface as `TimeZonePanel.gorm`, and quit Gorm. Don't
generate the files for class `TimeView` because I already have the
files. GNUstep can figure out where the classes are and where the
outlets/actions are.
### The code
Now, I need to add the new outlets and actions into the files of
`TimeView`. Here is the header.
`TimeView.h:`
```objc
#import
#import "ClockView.h"
@interface TimeView : NSControl
{
id zonePanel;
id zoneField;
NSBox* box;
NSTextField *labelDate, *labelTime;
NSTextField *localDate, *localTime;
NSCalendarDate* date;
ClockView* clockView;
}
- (NSCalendarDate *) date;
- (void) setDate: (NSCalendarDate *) date;
- (void) okAction: (id) sender;
- (void) cancelAction: (id) sender;
@end
```
I add the outlets and actions by myself.
`TimeView.m:`
```objc
- (void) mouseDown: (NSEvent *) event {
NSRect titleFrame = [box titleRect];
NSPoint windowLocation = [event locationInWindow];
NSPoint viewLocation = [self convertPoint: windowLocation fromView: [self superview]];
BOOL status = NSMouseInRect(viewLocation, titleFrame, NO);
if (status == YES) {
[NSBundle loadNibNamed: @"TimeZonePanel.gorm" owner: self];
[NSApp runModalForWindow: self->zonePanel];
}
}
```
The method `-mouseDown:` is called when mouse is clicked within this view.
Here, we calculate whether the mouse is clicked in the area of the title
of the `NSBox`. If so, we use `[NSBundle loadNibNamed: owner:]` to load the
window, and `[NSApp runModalForWindow]` to display it. Read Cocoa's
document about "[*How Modal Windows
Work*](http://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/ProgrammingTopics/WinPanel/Concepts/UsingModalWindows.html#CJBEADBA)".
Now, I just need to finish the actions part in `TimeView.m`.
`TimeView.m:`
```objc
- (void) cancelAction: (id) sender
{
[NSApp abortModal];
[self->zonePanel close];
}
- (void) okAction: (id) sender
{
NSTimeZone* tempZone;
tempZone = [NSTimeZone timeZoneWithName: [zoneField stringValue]];
[NSApp stopModal];
[zonePanel close];
if (tempZone == nil) {
NSRunAlertPanel(@"Warning!",
@"Wrong Time Zone !!",
@"OK", nil, nil);
} else {
[date setTimeZone: tempZone];
[box setTitle: [tempZone description]];
[self setDate: date];
}
}
```
In method `-okAction:`, I use a built-in panel, `NSRunAlertPanel`. There are
several built-in panels in GNUstep ready to use. Now, you can display
the current time in different time zone.
## Better keyboard access
It is inconvenient to use this pop-up panel because you have to click
the `NSTextField` before typing. Sometimes, it is more convenient to
control the user interface via keyboard rather than mouse.
When a window pop-up, it is the "First Responder" -- the first object
to receive events and keypresses. But usually we want some
other objects in this window to receive the keypresses. Therefore, we need
to change the "first responder" of this window by
using `[NSWindow makeFirstResponder:]`.
When I want to use Tab key to switch between different views in the
window, you need to assign the `nextKeyView` to the next view when the Tab
key is pressed so that the Application Kit knows where the responder should
be.
Finally, when I finish typing in the `NSTextField`, I want to hit the
Return key to click so that I
don't need to move my hand out of the keyboard. In this case, since
`NSTextField` is also a subclass of `NSControl`, I can set the target and
action of `NSTextField` to be the same as the `NSButton` . Therefore, when I hit Return, it is equivalent to clicking on the button.
These are small tune-ups for the application, but it makes it easier to use the application.
First, let's set the "first responder" of the window to the
NSTextField:
`TimeView.m:`
```objc
- (void) mouseDown: (NSEvent *) event
{
NSRect titleFrame = [self->box titleRect];
NSPoint windowLocation = [event locationInWindow];
NSPoint viewLocation = [self convertPoint: windowLocation fromView: [self superview]];
BOOL status = NSMouseInRect(viewLocation, titleFrame, NO);
if (status == YES) {
[NSBundle loadNibNamed: @"TimeZonePanel.gorm" owner: self];
[self->zonePanel makeFirstResponder: zoneField];
[NSApp runModalForWindow: self->zonePanel];
}
}
```
Only one line is enough. Now, when this panel shows up, the cursor will
automatically be in the `NSTextField`.
Second, let's set the target and action of `NSTextField` to be the same as the `NSButton` . Open the `TimeZonePanel.gorm`, and connect the `NSTextField` to the method `-okAction:` of the `NSOwner`. That's it. Whenever you hit the Return key in the `NSTextField`, the method `-okAction:` is
called.
**Figure 4-29. Connection NSTextField action**
![](GSPT_files/Panel-10.jpg)
![](GSPT_files/Panel-11.jpg)
![](GSPT_files/Panel-12.jpg)
Third, we need to connect the `nextKeyView` outlet between the views in
the window. I'll connect the `nextKeyView` of `NSTextField` to the `NSButton` , the `nextKeyView` outlet of the `NSButton` to the `NSButton` ,
and the `nextKeyView` outlet of the `NSButton` to the `NSTextField`. By
doing that, I can switch between these views using the Tab key. Here, I just
show how the `nextKeyView` of `NSTextField` connects to the `NSButton` .
**Figure 4-30. Connect nextKeyView**
![](GSPT_files/Panel-13.jpg)
![](GSPT_files/Panel-14.jpg)
Source code:
[Panel-src.tar.gz](http://gnustep.made-it.com/GSPT/Panel/Panel-src.tar.gz).